$extrastylesheet
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