euler2_solver.C
Go to the documentation of this file.00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2012 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 unsigned int n_dofs = context.elem_solution.size(); 00054 00055 // Local nonlinear solution at old timestep 00056 DenseVector<Number> old_elem_solution(n_dofs); 00057 for (unsigned int i=0; i != n_dofs; ++i) 00058 old_elem_solution(i) = 00059 old_nonlinear_solution(context.dof_indices[i]); 00060 00061 // We evaluate mass_residual with the change in solution 00062 // to get the mass matrix, reusing old_elem_solution to hold that 00063 // delta_solution. 00064 DenseVector<Number> delta_elem_solution(context.elem_solution); 00065 delta_elem_solution -= old_elem_solution; 00066 00067 // Our first evaluations are at the true elem_solution 00068 context.elem_solution_derivative = 1.0; 00069 00070 // If a fixed solution is requested, we'll use the elem_solution 00071 // at the new timestep 00072 if (_system.use_fixed_solution) 00073 context.elem_fixed_solution = context.elem_solution; 00074 00075 context.fixed_solution_derivative = 1.0; 00076 00077 // We're going to compute just the change in elem_residual 00078 // (and possibly elem_jacobian), then add back the old values 00079 DenseVector<Number> total_elem_residual(context.elem_residual); 00080 DenseMatrix<Number> old_elem_jacobian, total_elem_jacobian; 00081 if (request_jacobian) 00082 { 00083 old_elem_jacobian = context.elem_jacobian; 00084 total_elem_jacobian = context.elem_jacobian; 00085 context.elem_jacobian.zero(); 00086 } 00087 context.elem_residual.zero(); 00088 00089 // First, evaluate time derivative at the new timestep. 00090 // The element should already be in the proper place 00091 // even for a moving mesh problem. 00092 bool jacobian_computed = 00093 _system.element_time_derivative(request_jacobian, context); 00094 00095 // For a moving mesh problem we may need the pseudoconvection term too 00096 jacobian_computed = 00097 _system.eulerian_residual(jacobian_computed, context) && jacobian_computed; 00098 00099 // Scale the new time-dependent residual and jacobian correctly 00100 context.elem_residual *= (theta * _system.deltat); 00101 total_elem_residual += context.elem_residual; 00102 context.elem_residual.zero(); 00103 00104 if (jacobian_computed) 00105 { 00106 context.elem_jacobian *= (theta * _system.deltat); 00107 total_elem_jacobian += context.elem_jacobian; 00108 context.elem_jacobian.zero(); 00109 } 00110 00111 // Next, evaluate the mass residual at the new timestep, 00112 // with the delta_solution. 00113 // Evaluating the mass residual at both old and new timesteps will be 00114 // redundant in most problems but may be necessary for time accuracy 00115 // or stability in moving mesh problems or problems with user-overridden 00116 // mass_residual functions 00117 00118 // Move elem_->delta_, delta_->elem_ 00119 context.elem_solution.swap(delta_elem_solution); 00120 00121 jacobian_computed = _system.mass_residual(jacobian_computed, context) && 00122 jacobian_computed; 00123 00124 context.elem_residual *= -theta; 00125 total_elem_residual += context.elem_residual; 00126 context.elem_residual.zero(); 00127 00128 if (jacobian_computed) 00129 { 00130 // The minus sign trick here is to avoid using a non-1 00131 // elem_solution_derivative: 00132 context.elem_jacobian *= -theta; 00133 total_elem_jacobian += context.elem_jacobian; 00134 context.elem_jacobian.zero(); 00135 } 00136 00137 // Add the time-dependent term for the old solution 00138 00139 // Make sure elem_solution is set up for elem_reinit to use 00140 // Move delta_->old_, old_->elem_ 00141 context.elem_solution.swap(old_elem_solution); 00142 00143 // Move the mesh into place first if necessary 00144 context.elem_reinit(0.); 00145 00146 if (_system.use_fixed_solution) 00147 { 00148 context.elem_solution_derivative = 0.0; 00149 jacobian_computed = 00150 _system.element_time_derivative(jacobian_computed, context) && 00151 jacobian_computed; 00152 jacobian_computed = 00153 _system.eulerian_residual(jacobian_computed, context) && 00154 jacobian_computed; 00155 context.elem_solution_derivative = 1.0; 00156 context.elem_residual *= ((1. - theta) * _system.deltat); 00157 total_elem_residual += context.elem_residual; 00158 if (jacobian_computed) 00159 { 00160 context.elem_jacobian *= ((1. - theta) * _system.deltat); 00161 total_elem_jacobian += context.elem_jacobian; 00162 context.elem_jacobian.zero(); 00163 } 00164 } 00165 else 00166 { 00167 // FIXME - we should detect if element_time_derivative() edits 00168 // elem_jacobian and lies about it! 00169 _system.element_time_derivative(false, context); 00170 _system.eulerian_residual(false, context); 00171 context.elem_residual *= ((1. - theta) * _system.deltat); 00172 total_elem_residual += context.elem_residual; 00173 } 00174 00175 context.elem_residual.zero(); 00176 00177 // Add the mass residual term for the old solution 00178 00179 // Move old_->old_, delta_->elem_ 00180 context.elem_solution.swap(old_elem_solution); 00181 00182 jacobian_computed = _system.mass_residual(jacobian_computed, context) && 00183 jacobian_computed; 00184 00185 context.elem_residual *= -(1. - theta); 00186 total_elem_residual += context.elem_residual; 00187 context.elem_residual.zero(); 00188 00189 if (jacobian_computed) 00190 { 00191 // The minus sign trick here is to avoid using a non-1 00192 // *_solution_derivative: 00193 context.elem_jacobian *= -(1. - theta); 00194 total_elem_jacobian += context.elem_jacobian; 00195 context.elem_jacobian.zero(); 00196 } 00197 00198 // Restore the elem_solution 00199 // Move elem_->elem_, delta_->delta_ 00200 context.elem_solution.swap(delta_elem_solution); 00201 00202 // Restore the elem position if necessary 00203 context.elem_reinit(1.); 00204 00205 // Add the constraint term 00206 jacobian_computed = _system.element_constraint(jacobian_computed, context) && 00207 jacobian_computed; 00208 00209 // Add back the previously accumulated residual and jacobian 00210 context.elem_residual += total_elem_residual; 00211 if (request_jacobian) 00212 { 00213 if (jacobian_computed) 00214 context.elem_jacobian += total_elem_jacobian; 00215 else 00216 context.elem_jacobian.swap(old_elem_jacobian); 00217 } 00218 00219 return jacobian_computed; 00220 } 00221 00222 00223 00224 bool Euler2Solver::side_residual (bool request_jacobian, 00225 DiffContext &context) 00226 { 00227 unsigned int n_dofs = context.elem_solution.size(); 00228 00229 // Local nonlinear solution at old timestep 00230 DenseVector<Number> old_elem_solution(n_dofs); 00231 for (unsigned int i=0; i != n_dofs; ++i) 00232 old_elem_solution(i) = 00233 old_nonlinear_solution(context.dof_indices[i]); 00234 00235 // We evaluate mass_residual with the change in solution 00236 // to get the mass matrix, reusing old_elem_solution to hold that 00237 // delta_solution. 00238 DenseVector<Number> delta_elem_solution(context.elem_solution); 00239 delta_elem_solution -= old_elem_solution; 00240 00241 // Our first evaluations are at the true elem_solution 00242 context.elem_solution_derivative = 1.0; 00243 00244 // If a fixed solution is requested, we'll use the elem_solution 00245 // at the new timestep 00246 if (_system.use_fixed_solution) 00247 context.elem_fixed_solution = context.elem_solution; 00248 00249 context.fixed_solution_derivative = 1.0; 00250 00251 // We're going to compute just the change in elem_residual 00252 // (and possibly elem_jacobian), then add back the old values 00253 DenseVector<Number> total_elem_residual(context.elem_residual); 00254 DenseMatrix<Number> old_elem_jacobian, total_elem_jacobian; 00255 if (request_jacobian) 00256 { 00257 old_elem_jacobian = context.elem_jacobian; 00258 total_elem_jacobian = context.elem_jacobian; 00259 context.elem_jacobian.zero(); 00260 } 00261 context.elem_residual.zero(); 00262 00263 // First, evaluate time derivative at the new timestep. 00264 // The element should already be in the proper place 00265 // even for a moving mesh problem. 00266 bool jacobian_computed = 00267 _system.side_time_derivative(request_jacobian, context); 00268 00269 // Scale the time-dependent residual and jacobian correctly 00270 context.elem_residual *= (theta * _system.deltat); 00271 total_elem_residual += context.elem_residual; 00272 context.elem_residual.zero(); 00273 00274 if (jacobian_computed) 00275 { 00276 context.elem_jacobian *= (theta * _system.deltat); 00277 total_elem_jacobian += context.elem_jacobian; 00278 context.elem_jacobian.zero(); 00279 } 00280 00281 // Next, evaluate the mass residual at the new timestep, 00282 // with the delta_solution. 00283 // Evaluating the mass residual at both old and new timesteps will be 00284 // redundant in most problems but may be necessary for time accuracy 00285 // or stability in moving mesh problems or problems with user-overridden 00286 // mass_residual functions 00287 00288 // Move elem_->delta_, delta_->elem_ 00289 context.elem_solution.swap(delta_elem_solution); 00290 00291 jacobian_computed = _system.side_mass_residual(jacobian_computed, context) && 00292 jacobian_computed; 00293 00294 context.elem_residual *= -theta; 00295 total_elem_residual += context.elem_residual; 00296 context.elem_residual.zero(); 00297 00298 if (jacobian_computed) 00299 { 00300 // The minus sign trick here is to avoid using a non-1 00301 // elem_solution_derivative: 00302 context.elem_jacobian *= -theta; 00303 total_elem_jacobian += context.elem_jacobian; 00304 context.elem_jacobian.zero(); 00305 } 00306 00307 // Add the time-dependent term for the old solution 00308 00309 // Make sure elem_solution is set up for elem_reinit to use 00310 // Move delta_->old_, old_->elem_ 00311 context.elem_solution.swap(old_elem_solution); 00312 00313 // Move the mesh into place first if necessary 00314 context.elem_side_reinit(0.); 00315 00316 if (_system.use_fixed_solution) 00317 { 00318 context.elem_solution_derivative = 0.0; 00319 jacobian_computed = 00320 _system.side_time_derivative(jacobian_computed, context) && 00321 jacobian_computed; 00322 context.elem_solution_derivative = 1.0; 00323 context.elem_residual *= ((1. - theta) * _system.deltat); 00324 total_elem_residual += context.elem_residual; 00325 if (jacobian_computed) 00326 { 00327 context.elem_jacobian *= ((1. - theta) * _system.deltat); 00328 total_elem_jacobian += context.elem_jacobian; 00329 context.elem_jacobian.zero(); 00330 } 00331 } 00332 else 00333 { 00334 // FIXME - we should detect if side_time_derivative() edits 00335 // elem_jacobian and lies about it! 00336 _system.side_time_derivative(false, context); 00337 context.elem_residual *= ((1. - theta) * _system.deltat); 00338 total_elem_residual += context.elem_residual; 00339 } 00340 00341 context.elem_residual.zero(); 00342 00343 // Add the mass residual term for the old solution 00344 00345 // Move old_->old_, delta_->elem_ 00346 context.elem_solution.swap(old_elem_solution); 00347 00348 jacobian_computed = 00349 _system.side_mass_residual(jacobian_computed, context) && 00350 jacobian_computed; 00351 00352 context.elem_residual *= -(1. - theta); 00353 total_elem_residual += context.elem_residual; 00354 context.elem_residual.zero(); 00355 00356 if (jacobian_computed) 00357 { 00358 // The minus sign trick here is to avoid using a non-1 00359 // *_solution_derivative: 00360 context.elem_jacobian *= -(1. - theta); 00361 total_elem_jacobian += context.elem_jacobian; 00362 context.elem_jacobian.zero(); 00363 } 00364 00365 // Restore the elem_solution 00366 // Move elem_->elem_, delta_->delta_ 00367 context.elem_solution.swap(delta_elem_solution); 00368 00369 // Restore the elem position if necessary 00370 context.elem_side_reinit(1.); 00371 00372 // Add the constraint term 00373 jacobian_computed = _system.side_constraint(jacobian_computed, context) && 00374 jacobian_computed; 00375 00376 // Add back the previously accumulated residual and jacobian 00377 context.elem_residual += total_elem_residual; 00378 if (request_jacobian) 00379 { 00380 if (jacobian_computed) 00381 context.elem_jacobian += total_elem_jacobian; 00382 else 00383 context.elem_jacobian.swap(old_elem_jacobian); 00384 } 00385 00386 return jacobian_computed; 00387 } 00388 00389 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:46 UTC
Hosted By: