void EigenExecutionerBase::inversePowerIteration(unsigned int min_iter, unsigned int max_iter, Real pfactor, bool cheb_on, Real tol_eig, bool echo, PostprocessorName xdiff, Real tol_x, Real & k, Real & initial_res) { mooseAssert(max_iter>=min_iter, "Maximum number of power iterations must be greater than or equal to its minimum"); mooseAssert(pfactor>0.0, "Invaid linear convergence tolerance"); mooseAssert(tol_eig>0.0, "Invalid eigenvalue tolerance"); mooseAssert(tol_x>0.0, "Invalid solution norm tolerance"); // obtain the solution diff const PostprocessorValue * solution_diff = NULL; if (xdiff != "") { solution_diff = &getPostprocessorValueByName(xdiff); ExecFlagType xdiff_execflag = _problem.getUserObject<UserObject>(xdiff).execBitFlags(); if ((xdiff_execflag & EXEC_LINEAR) == EXEC_NONE) mooseError("Postprocessor "+xdiff+" requires execute_on = 'linear'"); } // not perform any iteration when max_iter==0 if (max_iter==0) return; // turn off nonlinear flag so that RHS kernels opterate on previous solutions _eigen_sys.eigenKernelOnOld(); // FIXME: currently power iteration use old and older solutions, // so save old and older solutions before they are changed by the power iteration _eigen_sys.saveOldSolutions(); // save solver control parameters to be modified by the power iteration Real tol1 = _problem.es().parameters.get<Real> ("linear solver tolerance"); unsigned int num1 = _problem.es().parameters.get<unsigned int>("nonlinear solver maximum iterations"); // every power iteration is a linear solve, so set nonlinear iteration number to one _problem.es().parameters.set<Real> ("linear solver tolerance") = pfactor; _problem.es().parameters.set<unsigned int>("nonlinear solver maximum iterations") = 1; if (echo) { _console << std::endl; _console << " Power iterations starts" << std::endl; _console << " ________________________________________________________________________________ " << std::endl; } // some iteration variables Real k_old = 0.0; Real & source_integral_old = getPostprocessorValueOld("bx_norm"); Real saved_source_integral_old = source_integral_old; Chebyshev_Parameters chebyshev_parameters; std::vector<Real> keff_history; std::vector<Real> diff_history; unsigned int iter = 0; // power iteration loop... // Note: |Bx|/k will stay constant one! makeBXConsistent(k); while (true) { if (echo) _console << " Power iteration= "<< iter << std::endl; // important: solutions of aux system is also copied _problem.advanceState(); k_old = k; source_integral_old = _source_integral; preIteration(); _problem.solve(); postIteration(); // save the initial residual if (iter==0) initial_res = _eigen_sys._initial_residual_before_preset_bcs; // update eigenvalue k = k_old * _source_integral / source_integral_old; _eigenvalue = k; if (echo) { // output on screen the convergence history only when we want to and MOOSE output system is not used keff_history.push_back(k); if (solution_diff) diff_history.push_back(*solution_diff); std::stringstream ss; if (solution_diff) { ss << std::endl; ss << " +================+=====================+=====================+\n"; ss << " | iteration | eigenvalue | solution_difference |\n"; ss << " +================+=====================+=====================+\n"; unsigned int j = 0; if (keff_history.size()>10) { ss << " : : : :\n"; j = keff_history.size()-10; } for (; j<keff_history.size(); j++) ss << " | " << std::setw(14) << j << " | " << std::setw(19) << std::scientific << std::setprecision(8) << keff_history[j] << " | " << std::setw(19) << std::scientific << std::setprecision(8) << diff_history[j] << " |\n"; ss << " +================+=====================+=====================+\n" << std::flush; } else { ss << std::endl; ss << " +================+=====================+\n"; ss << " | iteration | eigenvalue |\n"; ss << " +================+=====================+\n"; unsigned int j = 0; if (keff_history.size()>10) { ss << " : : :\n"; j = keff_history.size()-10; } for (; j<keff_history.size(); j++) ss << " | " << std::setw(14) << j << " | " << std::setw(19) << std::scientific << std::setprecision(8) << keff_history[j] << " |\n"; ss << " +================+=====================+\n" << std::flush; ss << std::endl; } _console << ss.str() << std::endl; } // increment iteration number here iter++; if (cheb_on) { chebyshev(chebyshev_parameters, iter, solution_diff); if (echo) _console << " Chebyshev step: " << chebyshev_parameters.icheb << std::endl; } if (echo) _console << " ________________________________________________________________________________ " << std::endl; // not perform any convergence check when number of iterations is less than min_iter if (iter>=min_iter) { // no need to check convergence of the last iteration if (iter!=max_iter) { bool converged = true; Real keff_error = fabs(k_old-k)/k; if (keff_error>tol_eig) converged = false; if (solution_diff) if (*solution_diff > tol_x) converged = false; if (converged) break; } else break; } } source_integral_old = saved_source_integral_old; // restore parameters changed by the executioner _problem.es().parameters.set<Real> ("linear solver tolerance") = tol1; _problem.es().parameters.set<unsigned int>("nonlinear solver maximum iterations") = num1; //FIXME: currently power iteration use old and older solutions, so restore them _eigen_sys.restoreOldSolutions(); }
void EigenExecutionerBase::inversePowerIteration(unsigned int min_iter, unsigned int max_iter, Real pfactor, bool cheb_on, Real tol_eig, Real tol_x, bool echo, bool output_convergence, Real time_base, Real & k, Real & initial_res) { mooseAssert(max_iter>=min_iter, "Maximum number of power iterations must be greater than or equal to its minimum"); mooseAssert(pfactor>0.0, "Invaid linear convergence tolerance"); mooseAssert(tol_eig>0.0, "Invalid eigenvalue tolerance"); mooseAssert(tol_x>0.0, "Invalid solution norm tolerance"); if ( _bx_execflag != EXEC_TIMESTEP && _bx_execflag != EXEC_RESIDUAL) mooseError("rhs postprocessor for the power method has to be executed on timestep or residual"); if ( _xdiff_execflag != EXEC_TIMESTEP && _xdiff_execflag != EXEC_RESIDUAL) mooseError("xdiff postprocessor for the power method has to be executed on timestep or residual"); // not perform any iteration when max_iter==0 if (max_iter==0) return; // turn off nonlinear flag so that RHS kernels opterate on previous solutions _eigen_sys.eigenKernelOnOld(); // FIXME: currently power iteration use old and older solutions, // so save old and older solutions before they are changed by the power iteration _eigen_sys.saveOldSolutions(); // _es.parameters.print(Moose::out); // save solver control parameters to be modified by the power iteration Real tol1 = _problem.es().parameters.get<Real> ("linear solver tolerance"); unsigned int num1 = _problem.es().parameters.get<unsigned int>("nonlinear solver maximum iterations"); // every power iteration is a linear solve, so set nonlinear iteration number to one _problem.es().parameters.set<Real> ("linear solver tolerance") = pfactor; _problem.es().parameters.set<unsigned int>("nonlinear solver maximum iterations") = 1; if (echo) { Moose::out << std::endl; Moose::out << " Power iterations starts" << std::endl; Moose::out << " ________________________________________________________________________________ " << std::endl; } // some iteration variables Real k_old = 0.0; std::vector<Real> keff_history; std::vector<Real> diff_history; unsigned int iter = 0; // power iteration loop... // Note: |Bx|/k will stay constant one! makeBXConsistent(k); while (true) { if (echo) Moose::out << " Power iteration= "<< iter << std::endl; // important: solutions of aux system is also copied _problem.copyOldSolutions(); _problem.updateMaterials(); k_old = k; // FIXME: timestep needs to be changed to step _problem.onTimestepBegin(); // this will copy postprocessors to old _problem.timestepSetup(); _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::PRE_AUX); _problem.computeAuxiliaryKernels(EXEC_TIMESTEP_BEGIN); _problem.computeUserObjects(EXEC_TIMESTEP_BEGIN, UserObjectWarehouse::POST_AUX); preIteration(); _problem.solve(); postIteration(); // FIXME: timestep needs to be changed to step _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::PRE_AUX); _problem.computeAuxiliaryKernels(EXEC_TIMESTEP); _problem.computeUserObjects(EXEC_TIMESTEP, UserObjectWarehouse::POST_AUX); _problem.onTimestepEnd(); // save the initial residual if (iter==0) initial_res = _eigen_sys._initial_residual; // update eigenvalue k = k_old * _source_integral / _source_integral_old; // synchronize _eigenvalue with |Bx| for output purpose // Note: if using MOOSE output system, eigenvalue output will be one iteration behind. // Also this will affect EigenKernels with eigen=false. _eigenvalue = k; if (echo && (!output_convergence)) { // output on screen the convergence history only when we want to and MOOSE output system is not used keff_history.push_back(k); if (_solution_diff) diff_history.push_back(*_solution_diff); std::ios_base::fmtflags flg = Moose::out.flags(); std::streamsize pcs = Moose::out.precision(); if (_solution_diff) { Moose::out << std::endl; Moose::out << " +================+=====================+=====================+\n"; Moose::out << " | iteration | eigenvalue | solution_difference |\n"; Moose::out << " +================+=====================+=====================+\n"; unsigned int j = 0; if (keff_history.size()>10) { Moose::out << " : : : :\n"; j = keff_history.size()-10; } for (; j<keff_history.size(); j++) Moose::out << " | " << std::setw(14) << j << " | " << std::setw(19) << std::scientific << std::setprecision(8) << keff_history[j] << " | " << std::setw(19) << std::scientific << std::setprecision(8) << diff_history[j] << " |\n"; Moose::out << " +================+=====================+=====================+\n" << std::flush; Moose::out << std::endl; } else { Moose::out << std::endl; Moose::out << " +================+=====================+\n"; Moose::out << " | iteration | eigenvalue |\n"; Moose::out << " +================+=====================+\n"; unsigned int j = 0; if (keff_history.size()>10) { Moose::out << " : : :\n"; j = keff_history.size()-10; } for (; j<keff_history.size(); j++) Moose::out << " | " << std::setw(14) << j << " | " << std::setw(19) << std::scientific << std::setprecision(8) << keff_history[j] << " |\n"; Moose::out << " +================+=====================+\n" << std::flush; Moose::out << std::endl; } Moose::out.flags(flg); Moose::out.precision(pcs); } // increment iteration number here iter++; if (cheb_on) { chebyshev(iter); if (echo) Moose::out << " Chebyshev step: " << chebyshev_parameters.icheb << std::endl; } if (echo) Moose::out << " ________________________________________________________________________________ " << std::endl; // not perform any convergence check when number of iterations is less than min_iter if (iter>=min_iter) { // no need to check convergence of the last iteration if (iter!=max_iter) { bool converged = true; Real keff_error = fabs(k_old-k)/k; if (keff_error>tol_eig) converged = false; if (_solution_diff) if (*_solution_diff > tol_x) converged = false; if (converged) break; } else break; } // use output system to dump iteration history if (output_convergence) { // we need to tempararily change system time to obtain the right output // FIXME: if 'step' capability is available, we will not need to do this. Real t = _problem.time(); _problem.time() = time_base + Real(iter)/max_iter; _output_warehouse.outputStep(); _problem.time() = t; } } // restore parameters changed by the executioner _problem.es().parameters.set<Real> ("linear solver tolerance") = tol1; _problem.es().parameters.set<unsigned int>("nonlinear solver maximum iterations") = num1; //FIXME: currently power iteration use old and older solutions, so restore them _eigen_sys.restoreOldSolutions(); }