4 #define BOOST_LOG_DYN_LINK 1 5 #include <boost/log/trivial.hpp> 8 inline size_t power(
size_t a,
size_t b){
10 for(
size_t i = 0; i < b; i++) {
14 assert( (
pow(1.0*a,1.0*b) -
double(res)) < 0.5);
23 template<
size_t NDIM,
typename T>
27 size_t i = index_list[0];
30 kinetic = -2.0 * NDIM * _f[level][ i ];
31 for(
size_t k = 1; k < 2*NDIM + 1; k++){
32 kinetic += _f[level][ index_list[k] ];
36 T *rho = _ext_field[0]->get_y(level);
40 if( level > 0 && addsource ){
41 source += _source[level][i];
45 l = kinetic/(h*
h) - source;
55 template<
size_t NDIM,
typename T>
59 T dl = -2.0*NDIM/(h*
h);
63 BOOST_LOG_TRIVIAL(error) <<
"Error: dl close to 0" << std::endl;
76 template<
size_t NDIM,
typename T>
79 T l = l_operator(level, index_list,
true, h);
80 T dl = dl_operator(level, index_list, h);
88 template<
size_t NDIM,
typename T>
92 _tot_sweeps_domain_grid = 0;
93 _res_domain_array.clear();
96 BOOST_LOG_TRIVIAL(debug) << std::endl;
97 BOOST_LOG_TRIVIAL(debug) <<
"===============================================================" << std::endl;
98 BOOST_LOG_TRIVIAL(debug) <<
"==> Starting multigrid solver" << std::endl;
99 BOOST_LOG_TRIVIAL(debug) <<
"===============================================================\n" << std::endl;
103 solve_current_level(0);
106 _rms_res_i = _rms_res;
113 while(status == Exit_Status::ITERATE) {
117 BOOST_LOG_TRIVIAL(debug) << std::endl;
118 BOOST_LOG_TRIVIAL(debug) <<
"===============================================================" << std::endl;
119 BOOST_LOG_TRIVIAL(debug) <<
"==> Starting V-cycle istep = " << _istep_vcycle <<
" Res = " << _rms_res << std::endl;
120 BOOST_LOG_TRIVIAL(debug) <<
"===============================================================\n" << std::endl;
125 solve_current_level(0);
128 recursive_go_down(0);
131 recursive_go_up(_Nlevel-2);
135 _f.get_grid(0).check_for_nan(
true);
138 status = check_convergence();
144 template<
size_t NDIM,
typename T>
146 return _f.get_y(level);
149 template<
size_t NDIM,
typename T>
151 return _f.get_y(level);
154 template<
size_t NDIM,
typename T>
156 _eps_converge = eps_converge;
159 template<
size_t NDIM,
typename T>
162 _ext_field.push_back(field);
165 template<
size_t NDIM,
typename T>
167 _maxsteps = maxsteps;
170 template<
size_t NDIM,
typename T>
172 _conv_criterion_residual = use_residual;
175 template<
size_t NDIM,
typename T>
177 _ngs_fine = ngs_fine;
178 _ngs_coarse = ngs_coarse;
181 template<
size_t NDIM,
typename T>
184 assert( ( _N /
power(2, N - 1) ) *
power(2, N - 1) == _N);
193 template<
size_t NDIM,
typename T>
195 return _f.get_N(level);
198 template<
size_t NDIM,
typename T>
200 return _f.get_Ntot(level);
203 template<
size_t NDIM,
typename T>
208 template<
size_t NDIM,
typename T>
210 _N(N), _Ntot(
power(N, NDIM)), _Nmin(Nmin), _Nlevel(int(log2(N / _Nmin) + 1)), _verbose(verbose),
211 _rms_res(0.0), _rms_res_i(0.0), _rms_res_old(0.0) {
230 template<
size_t NDIM,
typename T>
233 std::fill_n(f,
_Ntot, guess);
236 template<
size_t NDIM,
typename T>
239 std::copy( &guess[0], &guess[0] +
_Ntot, &f[0] );
242 template<
size_t NDIM,
typename T>
245 T *guess = guessgrid.
get_y();
246 std::copy( &guess[0], &guess[0] +
_Ntot, &f[0] );
262 template<
size_t NDIM,
typename T>
264 index_list = std::vector<size_t>(2*NDIM+1);
266 for(
size_t j = 0, n = 1; j < NDIM; j++, n *= N){
268 size_t iminus = ii >= 1 ? ii - 1 : N - 1;
269 size_t iplus = ii <= N-2 ? ii + 1 : 0;
270 index_list[2*j+1] = i + (iminus - ii) * n;
271 index_list[2*j+2] = i + (iplus - ii) * n;
281 template<
size_t NDIM,
typename T>
283 size_t N =
get_N(level);
291 #pragma omp parallel for 293 for (
size_t i = 0; i < Ntot; i++) {
294 std::vector<size_t> index_list;
296 res[i] = -
l_operator(level, index_list,
true, h);
310 template<
size_t NDIM,
typename T>
318 BOOST_LOG_TRIVIAL(debug) <<
" Checking for convergence at step = " <<
_istep_vcycle << std::endl;
319 BOOST_LOG_TRIVIAL(debug) <<
" Residual = " <<
_rms_res <<
" Residual_old = " <<
_rms_res_old << std::endl;
320 BOOST_LOG_TRIVIAL(debug) <<
" Residual_i = " <<
_rms_res_i <<
" Err = " << err << std::endl;
329 BOOST_LOG_TRIVIAL(debug) << std::endl;
335 BOOST_LOG_TRIVIAL(debug) <<
" The solution has not yet converged res = " <<
_rms_res <<
" !< " <<
_eps_converge << std::endl;
344 BOOST_LOG_TRIVIAL(debug) << std::endl;
345 BOOST_LOG_TRIVIAL(debug) <<
" The solution has converged err = " << err <<
" < " <<
_eps_converge <<
" ( res = " <<
_rms_res <<
" ) istep = " <<
_istep_vcycle <<
"\n" << std::endl;
350 BOOST_LOG_TRIVIAL(debug) <<
" The solution has not yet converged err = " << err <<
" !< " <<
_eps_converge << std::endl;
356 BOOST_LOG_TRIVIAL(debug) <<
" Warning: Residual_old > Residual" << std::endl;
361 BOOST_LOG_TRIVIAL(debug) <<
" WARNING: MultigridSolver failed to converge! Reached istep = maxsteps = " <<
_maxsteps << std::endl;
369 template<
size_t NDIM,
typename T>
372 template<
size_t NDIM,
typename T>
380 template<
size_t NDIM,
typename T>
382 size_t twotondim = 1 << NDIM;
383 size_t NTop =
get_N(to_level);
384 size_t NtotTop =
get_Ntot(to_level);
385 size_t NBottom = NTop/2;
388 std::vector<size_t> nBottomPow(NDIM, 1);
389 std::vector<size_t> nTopPow(NDIM, 1);
390 for(
size_t j = 0, n = 1,
m = 1; j < NDIM; j++, n *= NBottom,
m *= NTop){
397 #pragma omp parallel for 399 for (
size_t i = 0; i < NtotTop; i++) {
400 std::vector<double> fac(NDIM, 0.0);
401 std::vector<int> iplus(NDIM, 0);
408 for(
size_t j = 0; j < NDIM; j++){
409 size_t ii = i/nTopPow[j] % NTop;
410 size_t iiBottom = ii/2;
411 iplus[j] = (iiBottom == NBottom-1 ? 1 - NBottom : 1) * nBottomPow[j];
412 fac[j] = ii % 2 == 0 ? 0.0 : 1.0;
413 iBottom += iiBottom * nBottomPow[j];
414 norm *= (1.0 + fac[j]);
422 Top[i] = Bottom[iBottom];
423 for(
size_t k = 1; k < twotondim; k++){
424 double termfac = 1.0;
426 std::bitset<NDIM> bits = std::bitset<NDIM>(k);
427 for(
size_t j = 0; j < NDIM; j++){
428 iAdd = bits[j] * iplus[j];
429 termfac *= 1.0 + bits[j] * (fac[j] - 1.0) ;
431 Top[i] +=
T(termfac) * Bottom[iBottom + iAdd];
433 Top[i] *= 1.0/
T(norm);
443 template<
size_t NDIM,
typename T>
445 size_t N =
get_N(level);
452 #pragma omp parallel for 454 for (
size_t i = 0; i < Ntot; i++) {
457 for(
size_t j = 0, n = 1; j < NDIM; j++, n *= N){
458 color += ( i / n % N );
463 if( color == curcolor ){
466 std::vector<size_t> index_list;
477 template<
size_t NDIM,
typename T>
482 BOOST_LOG_TRIVIAL(debug) <<
" Performing Newton-Gauss-Seidel sweeps at level " << level << std::endl;
491 for (
size_t i = 0; i < ngs_sweeps; i++) {
503 if( (level > 0 && (i == 1 || i == ngs_sweeps-1) ) || (level == 0) ){
504 BOOST_LOG_TRIVIAL(debug) <<
" level = " << std::setw(5) << level <<
" NGS Sweep = " << std::setw(5) << i;
505 BOOST_LOG_TRIVIAL(debug) <<
" Residual = " << std::setw(10) <<
calculate_residual(level,
_res.get_grid(level)) << std::endl;
514 if(
_verbose) BOOST_LOG_TRIVIAL(debug) << std::endl;
531 template<
size_t NDIM,
typename T>
533 size_t from_level = to_level + 1;
536 _f.restrict_down(to_level,
_res.get_grid(from_level));
544 BOOST_LOG_TRIVIAL(debug) <<
" Prolonge solution from level: " << to_level+1 <<
" -> " << to_level << std::endl;
564 template<
size_t NDIM,
typename T>
577 template<
size_t NDIM,
typename T>
587 template<
size_t NDIM,
typename T>
589 size_t N =
get_N(level);
597 #pragma omp parallel for 599 for(
size_t i = 0; i < Ntot; i++){
600 std::vector<size_t> index_list;
611 template<
size_t NDIM,
typename T>
613 size_t to_level = from_level + 1;
618 BOOST_LOG_TRIVIAL(debug) <<
" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" << std::endl;
619 BOOST_LOG_TRIVIAL(debug) <<
" We have reached the bottom level = " << from_level <<
" Start going up." << std::endl;
620 BOOST_LOG_TRIVIAL(debug) <<
" - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -\n" << std::endl;
626 BOOST_LOG_TRIVIAL(debug) <<
" Going down from level " << from_level <<
" -> " << to_level << std::endl;
629 _res.restrict_down(from_level,
_res.get_grid(to_level));
630 _f.restrict_down(from_level,
_f.get_grid(to_level));
643 template<
size_t NDIM,
typename T>
MultiGrid< NDIM, T > _source
Grid< NDIM, T > & get_grid(size_t level=0)
size_t _tot_sweeps_domain_grid
void set_ngs_sweeps(size_t ngs_fine, size_t ngs_coarse)
T * get_y(size_t level=0)
void recursive_go_down(size_t from_level)
void make_prolongation_array(Grid< NDIM, T > &f, Grid< NDIM, T > &Rf, Grid< NDIM, T > &df)
void set_convergence_criterion_residual(bool use_residual)
size_t get_Nlevel() const
void set_epsilon(double eps_converge)
size_t get_N(size_t level=0) const
double calculate_residual(size_t level, Grid< NDIM, T > &res)
size_t get_Ntot(size_t level=0) const
std::vector< MultiGrid< NDIM, T > * > _ext_field
void solve_current_level(size_t level)
virtual T upd_operator(const T f, const size_t level, const std::vector< size_t > &index_list, const T h) const
size_t get_Nlevel() const
virtual T l_operator(const size_t level, const std::vector< size_t > &index_list, bool addsource, const T h) const
void recursive_go_up(size_t to_level)
size_t power(size_t a, size_t b)
void set_maxsteps(size_t maxsteps)
void make_new_source(size_t level)
void prolonge_up_array(size_t to_level, Grid< NDIM, T > &BottomGrid, Grid< NDIM, T > &TopGrid)
void set_initial_guess(T guess)
void set_Nlevel(size_t N)
MultiGrid< NDIM, T > _res
float pow(float base, unsigned long int exp)
void GaussSeidelSweep(size_t level, size_t curcolor, T *f)
virtual Exit_Status check_convergence()
virtual void check_solution(size_t level, Grid< NDIM, T > &sol)
void add_external_grid(MultiGrid< NDIM, T > *field)
bool _conv_criterion_residual
std::vector< double > _res_domain_array
void get_neighbor_gridindex(std::vector< size_t > &index_list, size_t i, size_t ngrid)
virtual T dl_operator(const size_t level, const std::vector< size_t > &index_list, const T h) const
virtual void correct_sol(Grid< NDIM, T > &f, const Grid< NDIM, T > &corr, const size_t level)