$extrastylesheet
unsteady_solver.C
Go to the documentation of this file.
00001 // The libMesh Finite Element Library.
00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
00003 
00004 // This library is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU Lesser General Public
00006 // License as published by the Free Software Foundation; either
00007 // version 2.1 of the License, or (at your option) any later version.
00008 
00009 // This library is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012 // Lesser General Public License for more details.
00013 
00014 // You should have received a copy of the GNU Lesser General Public
00015 // License along with this library; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 
00018 
00019 #include "libmesh/diff_solver.h"
00020 #include "libmesh/diff_system.h"
00021 #include "libmesh/dof_map.h"
00022 #include "libmesh/numeric_vector.h"
00023 #include "libmesh/unsteady_solver.h"
00024 
00025 namespace libMesh
00026 {
00027 
00028 
00029 
00030 UnsteadySolver::UnsteadySolver (sys_type& s)
00031   : TimeSolver(s),
00032     old_local_nonlinear_solution (NumericVector<Number>::build(s.comm())),
00033     first_solve                  (true),
00034     first_adjoint_step (true)
00035 {
00036 }
00037 
00038 
00039 
00040 UnsteadySolver::~UnsteadySolver ()
00041 {
00042 }
00043 
00044 
00045 
00046 void UnsteadySolver::init ()
00047 {
00048   TimeSolver::init();
00049 
00050   _system.add_vector("_old_nonlinear_solution");
00051 }
00052 
00053 
00054 
00055 void UnsteadySolver::init_data()
00056 {
00057   TimeSolver::init_data();
00058 
00059 #ifdef LIBMESH_ENABLE_GHOSTED
00060   old_local_nonlinear_solution->init (_system.n_dofs(), _system.n_local_dofs(),
00061                                       _system.get_dof_map().get_send_list(), false,
00062                                       GHOSTED);
00063 #else
00064   old_local_nonlinear_solution->init (_system.n_dofs(), false, SERIAL);
00065 #endif
00066 }
00067 
00068 
00069 
00070 void UnsteadySolver::reinit ()
00071 {
00072   TimeSolver::reinit();
00073 
00074 #ifdef LIBMESH_ENABLE_GHOSTED
00075   old_local_nonlinear_solution->init (_system.n_dofs(), _system.n_local_dofs(),
00076                                       _system.get_dof_map().get_send_list(), false,
00077                                       GHOSTED);
00078 #else
00079   old_local_nonlinear_solution->init (_system.n_dofs(), false, SERIAL);
00080 #endif
00081 
00082   // localize the old solution
00083   NumericVector<Number> &old_nonlinear_soln =
00084     _system.get_vector("_old_nonlinear_solution");
00085 
00086   old_nonlinear_soln.localize
00087     (*old_local_nonlinear_solution,
00088      _system.get_dof_map().get_send_list());
00089 }
00090 
00091 
00092 
00093 void UnsteadySolver::solve ()
00094 {
00095   if (first_solve)
00096     {
00097       advance_timestep();
00098       first_solve = false;
00099     }
00100 
00101   unsigned int solve_result = _diff_solver->solve();
00102 
00103   // If we requested the UnsteadySolver to attempt reducing dt after a
00104   // failed DiffSolver solve, check the results of the solve now.
00105   if (reduce_deltat_on_diffsolver_failure)
00106     {
00107       bool backtracking_failed =
00108         solve_result & DiffSolver::DIVERGED_BACKTRACKING_FAILURE;
00109 
00110       bool max_iterations =
00111         solve_result & DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;
00112 
00113       if (backtracking_failed || max_iterations)
00114         {
00115           // Cut timestep in half
00116           for (unsigned int nr=0; nr<reduce_deltat_on_diffsolver_failure; ++nr)
00117             {
00118               _system.deltat *= 0.5;
00119               libMesh::out << "Newton backtracking failed.  Trying with smaller timestep, dt="
00120                            << _system.deltat << std::endl;
00121 
00122               solve_result = _diff_solver->solve();
00123 
00124               // Check solve results with reduced timestep
00125               bool backtracking_still_failed =
00126                 solve_result & DiffSolver::DIVERGED_BACKTRACKING_FAILURE;
00127 
00128               bool backtracking_max_iterations =
00129                 solve_result & DiffSolver::DIVERGED_MAX_NONLINEAR_ITERATIONS;
00130 
00131               if (!backtracking_still_failed && !backtracking_max_iterations)
00132                 {
00133                   if (!quiet)
00134                     libMesh::out << "Reduced dt solve succeeded." << std::endl;
00135                   return;
00136                 }
00137             }
00138 
00139           // If we made it here, we still couldn't converge the solve after
00140           // reducing deltat
00141           libMesh::out << "DiffSolver::solve() did not succeed after "
00142                        << reduce_deltat_on_diffsolver_failure
00143                        << " attempts." << std::endl;
00144           libmesh_convergence_failure();
00145 
00146         } // end if (backtracking_failed || max_iterations)
00147     } // end if (reduce_deltat_on_diffsolver_failure)
00148 }
00149 
00150 
00151 
00152 void UnsteadySolver::advance_timestep ()
00153 {
00154   if (!first_solve)
00155     {
00156       // Store the solution, does nothing by default
00157       // User has to attach appropriate solution_history object for this to
00158       // actually store anything anywhere
00159       solution_history->store();
00160 
00161       _system.time += _system.deltat;
00162     }
00163 
00164   NumericVector<Number> &old_nonlinear_soln =
00165     _system.get_vector("_old_nonlinear_solution");
00166   NumericVector<Number> &nonlinear_solution =
00167     *(_system.solution);
00168 
00169   old_nonlinear_soln = nonlinear_solution;
00170 
00171   old_nonlinear_soln.localize
00172     (*old_local_nonlinear_solution,
00173      _system.get_dof_map().get_send_list());
00174 }
00175 
00176 
00177 
00178 void UnsteadySolver::adjoint_advance_timestep ()
00179 {
00180   // On the first call of this function, we dont save the adjoint solution or
00181   // decrement the time, we just call the retrieve function below
00182   if(!first_adjoint_step)
00183     {
00184       // Call the store function to store the last adjoint before decrementing the time
00185       solution_history->store();
00186       // Decrement the system time
00187       _system.time -= _system.deltat;
00188     }
00189   else
00190     {
00191       first_adjoint_step = false;
00192     }
00193 
00194   // Retrieve the primal solution vectors at this time using the
00195   // solution_history object
00196   solution_history->retrieve();
00197 
00198   // Dont forget to localize the old_nonlinear_solution !
00199   _system.get_vector("_old_nonlinear_solution").localize
00200     (*old_local_nonlinear_solution,
00201      _system.get_dof_map().get_send_list());
00202 }
00203 
00204 void UnsteadySolver::retrieve_timestep()
00205 {
00206   // Retrieve all the stored vectors at the current time
00207   solution_history->retrieve();
00208 
00209   // Dont forget to localize the old_nonlinear_solution !
00210   _system.get_vector("_old_nonlinear_solution").localize
00211     (*old_local_nonlinear_solution,
00212      _system.get_dof_map().get_send_list());
00213 }
00214 
00215 
00216 Number UnsteadySolver::old_nonlinear_solution(const dof_id_type global_dof_number)
00217   const
00218 {
00219   libmesh_assert_less (global_dof_number, _system.get_dof_map().n_dofs());
00220   libmesh_assert_less (global_dof_number, old_local_nonlinear_solution->size());
00221 
00222   return (*old_local_nonlinear_solution)(global_dof_number);
00223 }
00224 
00225 
00226 
00227 Real UnsteadySolver::du(const SystemNorm &norm) const
00228 {
00229 
00230   UniquePtr<NumericVector<Number> > solution_copy =
00231     _system.solution->clone();
00232 
00233   solution_copy->add(-1., _system.get_vector("_old_nonlinear_solution"));
00234 
00235   solution_copy->close();
00236 
00237   return _system.calculate_norm(*solution_copy, norm);
00238 }
00239 
00240 
00241 
00242 } // namespace libMesh