Ejemplo n.º 1
0
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();
}
Ejemplo n.º 2
0
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();
}