$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_system.h" 00020 #include "libmesh/euler2_solver.h" 00021 00022 namespace libMesh 00023 { 00024 00025 00026 00027 Euler2Solver::Euler2Solver (sys_type& s) 00028 : UnsteadySolver(s), theta(1.) 00029 { 00030 } 00031 00032 00033 00034 Euler2Solver::~Euler2Solver () 00035 { 00036 } 00037 00038 00039 00040 Real Euler2Solver::error_order() const 00041 { 00042 if (theta == 0.5) 00043 return 2.; 00044 return 1.; 00045 } 00046 00047 00048 00049 00050 bool Euler2Solver::element_residual (bool request_jacobian, 00051 DiffContext &context) 00052 { 00053 return this->_general_residual(request_jacobian, 00054 context, 00055 &DifferentiablePhysics::mass_residual, 00056 &DifferentiablePhysics::_eulerian_time_deriv, 00057 &DifferentiablePhysics::element_constraint, 00058 &DiffContext::elem_reinit); 00059 } 00060 00061 00062 00063 bool Euler2Solver::side_residual (bool request_jacobian, 00064 DiffContext &context) 00065 { 00066 return this->_general_residual(request_jacobian, 00067 context, 00068 &DifferentiablePhysics::side_mass_residual, 00069 &DifferentiablePhysics::side_time_derivative, 00070 &DifferentiablePhysics::side_constraint, 00071 &DiffContext::elem_side_reinit); 00072 } 00073 00074 00075 00076 bool Euler2Solver::nonlocal_residual (bool request_jacobian, 00077 DiffContext &context) 00078 { 00079 return this->_general_residual(request_jacobian, 00080 context, 00081 &DifferentiablePhysics::nonlocal_mass_residual, 00082 &DifferentiablePhysics::nonlocal_time_derivative, 00083 &DifferentiablePhysics::nonlocal_constraint, 00084 &DiffContext::nonlocal_reinit); 00085 } 00086 00087 00088 00089 bool Euler2Solver::_general_residual (bool request_jacobian, 00090 DiffContext &context, 00091 ResFuncType mass, 00092 ResFuncType time_deriv, 00093 ResFuncType constraint, 00094 ReinitFuncType reinit_func) 00095 { 00096 unsigned int n_dofs = context.get_elem_solution().size(); 00097 00098 // Local nonlinear solution at old timestep 00099 DenseVector<Number> old_elem_solution(n_dofs); 00100 for (unsigned int i=0; i != n_dofs; ++i) 00101 old_elem_solution(i) = 00102 old_nonlinear_solution(context.get_dof_indices()[i]); 00103 00104 // Local time derivative of solution 00105 context.get_elem_solution_rate() = context.get_elem_solution(); 00106 context.get_elem_solution_rate() -= old_elem_solution; 00107 context.elem_solution_rate_derivative = 1 / _system.deltat; 00108 context.get_elem_solution_rate() *= 00109 context.elem_solution_rate_derivative; 00110 00111 // Our first evaluations are at the final elem_solution 00112 context.elem_solution_derivative = 1.0; 00113 00114 // If a fixed solution is requested, we'll use the elem_solution 00115 // at the new timestep 00116 // FIXME - should this be the theta solution instead? 00117 if (_system.use_fixed_solution) 00118 context.get_elem_fixed_solution() = context.get_elem_solution(); 00119 00120 context.fixed_solution_derivative = 1.0; 00121 00122 // We need to save the old jacobian and old residual since we'll be 00123 // multiplying some of the new contributions by theta or 1-theta 00124 DenseMatrix<Number> old_elem_jacobian(n_dofs, n_dofs); 00125 DenseVector<Number> old_elem_residual(n_dofs); 00126 old_elem_residual.swap(context.get_elem_residual()); 00127 if (request_jacobian) 00128 old_elem_jacobian.swap(context.get_elem_jacobian()); 00129 00130 // Local time derivative of solution 00131 context.get_elem_solution_rate() = context.get_elem_solution(); 00132 context.get_elem_solution_rate() -= old_elem_solution; 00133 context.elem_solution_rate_derivative = 1 / _system.deltat; 00134 context.get_elem_solution_rate() *= 00135 context.elem_solution_rate_derivative; 00136 00137 // First, evaluate time derivative at the new timestep. 00138 // The element should already be in the proper place 00139 // even for a moving mesh problem. 00140 bool jacobian_computed = 00141 (_system.*time_deriv)(request_jacobian, context); 00142 00143 // Next, evaluate the mass residual at the new timestep 00144 00145 jacobian_computed = (_system.*mass)(jacobian_computed, context) && 00146 jacobian_computed; 00147 00148 // Add the constraint term 00149 jacobian_computed = (_system.*constraint)(jacobian_computed, context) && 00150 jacobian_computed; 00151 00152 // The new solution's contribution is scaled by theta 00153 context.get_elem_residual() *= theta; 00154 context.get_elem_jacobian() *= theta; 00155 00156 // Save the new solution's term 00157 DenseMatrix<Number> elem_jacobian_newterm(n_dofs, n_dofs); 00158 DenseVector<Number> elem_residual_newterm(n_dofs); 00159 elem_residual_newterm.swap(context.get_elem_residual()); 00160 if (request_jacobian) 00161 elem_jacobian_newterm.swap(context.get_elem_jacobian()); 00162 00163 // Add the time-dependent term for the old solution 00164 00165 // Make sure elem_solution is set up for elem_reinit to use 00166 // Move elem_->old_, old_->elem_ 00167 context.get_elem_solution().swap(old_elem_solution); 00168 context.elem_solution_derivative = 0.0; 00169 00170 // Move the mesh into place first if necessary 00171 (context.*reinit_func)(0.); 00172 00173 jacobian_computed = 00174 (_system.*time_deriv)(jacobian_computed, context) && 00175 jacobian_computed; 00176 00177 // Add the mass residual term for the old solution 00178 00179 // Evaluating the mass residual at both old and new timesteps will be 00180 // redundant in most problems but may be necessary for time accuracy 00181 // or stability in moving mesh problems or problems with user-overridden 00182 // mass_residual functions 00183 00184 jacobian_computed = 00185 (_system.*mass)(jacobian_computed, context) && 00186 jacobian_computed; 00187 00188 // The old solution's contribution is scaled by (1-theta) 00189 context.get_elem_residual() *= (1-theta); 00190 context.get_elem_jacobian() *= (1-theta); 00191 00192 // Restore the elem_solution 00193 // Move elem_->elem_, old_->old_ 00194 context.get_elem_solution().swap(old_elem_solution); 00195 context.elem_solution_derivative = 1; 00196 00197 // Restore the elem position if necessary 00198 (context.*reinit_func)(1.); 00199 00200 // Add back (or restore) the old residual/jacobian 00201 context.get_elem_residual() += old_elem_residual; 00202 if (request_jacobian) 00203 { 00204 if (jacobian_computed) 00205 context.get_elem_jacobian() += old_elem_jacobian; 00206 else 00207 context.get_elem_jacobian().swap(old_elem_jacobian); 00208 } 00209 00210 // Add the saved new-solution terms 00211 context.get_elem_residual() += elem_residual_newterm; 00212 if (jacobian_computed) 00213 context.get_elem_jacobian() += elem_jacobian_newterm; 00214 00215 return jacobian_computed; 00216 } 00217 00218 00219 00220 } // namespace libMesh