euler_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/euler_solver.h" 00021 00022 namespace libMesh 00023 { 00024 00025 00026 00027 EulerSolver::EulerSolver (sys_type& s) 00028 : UnsteadySolver(s), theta(1.) 00029 { 00030 } 00031 00032 00033 00034 EulerSolver::~EulerSolver () 00035 { 00036 } 00037 00038 00039 00040 Real EulerSolver::error_order() const 00041 { 00042 if (theta == 0.5) 00043 return 2.; 00044 return 1.; 00045 } 00046 00047 00048 00049 00050 bool EulerSolver::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 // Local nonlinear solution at time t_theta 00062 DenseVector<Number> theta_solution(context.elem_solution); 00063 theta_solution *= theta; 00064 theta_solution.add(1. - theta, old_elem_solution); 00065 00066 // Technically the elem_solution_derivative is either theta 00067 // or -1.0 in this implementation, but we scale the former part 00068 // ourselves 00069 context.elem_solution_derivative = 1.0; 00070 00071 // Technically the fixed_solution_derivative is always theta, 00072 // but we're scaling a whole jacobian by theta after these first 00073 // evaluations 00074 context.fixed_solution_derivative = 1.0; 00075 00076 // If a fixed solution is requested, we'll use theta_solution 00077 if (_system.use_fixed_solution) 00078 context.elem_fixed_solution = theta_solution; 00079 00080 // Move theta_->elem_, elem_->theta_ 00081 context.elem_solution.swap(theta_solution); 00082 00083 // Move the mesh into place first if necessary 00084 context.elem_reinit(theta); 00085 00086 // We're going to compute just the change in elem_residual 00087 // (and possibly elem_jacobian), then add back the old values 00088 DenseVector<Number> old_elem_residual(context.elem_residual); 00089 DenseMatrix<Number> old_elem_jacobian; 00090 if (request_jacobian) 00091 { 00092 old_elem_jacobian = context.elem_jacobian; 00093 context.elem_jacobian.zero(); 00094 } 00095 context.elem_residual.zero(); 00096 00097 // Get the time derivative at t_theta 00098 bool jacobian_computed = 00099 _system.element_time_derivative(request_jacobian, context); 00100 00101 // For a moving mesh problem we may need the pseudoconvection term too 00102 jacobian_computed = 00103 _system.eulerian_residual(jacobian_computed, context) && jacobian_computed; 00104 00105 // Scale the time-dependent residual and jacobian correctly 00106 context.elem_residual *= _system.deltat; 00107 if (jacobian_computed) 00108 context.elem_jacobian *= (theta * _system.deltat); 00109 00110 // The fixed_solution_derivative is always theta, 00111 // and now we're done scaling jacobians 00112 context.fixed_solution_derivative = theta; 00113 00114 // We evaluate mass_residual with the change in solution 00115 // to get the mass matrix, reusing old_elem_solution to hold that 00116 // delta_solution. We're solving dt*F(u) - du = 0, so our 00117 // delta_solution is old_solution - new_solution. 00118 // We're still keeping elem_solution in theta_solution for now 00119 old_elem_solution -= theta_solution; 00120 00121 // Move old_->elem_, theta_->old_ 00122 context.elem_solution.swap(old_elem_solution); 00123 00124 // We do a trick here to avoid using a non-1 00125 // elem_solution_derivative: 00126 context.elem_jacobian *= -1.0; 00127 jacobian_computed = _system.mass_residual(jacobian_computed, context) && 00128 jacobian_computed; 00129 context.elem_jacobian *= -1.0; 00130 00131 // Move elem_->elem_, old_->theta_ 00132 context.elem_solution.swap(theta_solution); 00133 00134 // Restore the elem position if necessary 00135 context.elem_reinit(1.); 00136 00137 // Add the constraint term 00138 jacobian_computed = _system.element_constraint(jacobian_computed, context) && 00139 jacobian_computed; 00140 00141 // Add back the old residual and jacobian 00142 context.elem_residual += old_elem_residual; 00143 if (request_jacobian) 00144 { 00145 if (jacobian_computed) 00146 context.elem_jacobian += old_elem_jacobian; 00147 else 00148 context.elem_jacobian.swap(old_elem_jacobian); 00149 } 00150 00151 return jacobian_computed; 00152 } 00153 00154 00155 00156 bool EulerSolver::side_residual (bool request_jacobian, 00157 DiffContext &context) 00158 { 00159 unsigned int n_dofs = context.elem_solution.size(); 00160 00161 // Local nonlinear solution at old timestep 00162 DenseVector<Number> old_elem_solution(n_dofs); 00163 for (unsigned int i=0; i != n_dofs; ++i) 00164 old_elem_solution(i) = 00165 old_nonlinear_solution(context.dof_indices[i]); 00166 00167 // Local nonlinear solution at time t_theta 00168 DenseVector<Number> theta_solution(context.elem_solution); 00169 theta_solution *= theta; 00170 theta_solution.add(1. - theta, old_elem_solution); 00171 00172 // Technically the elem_solution_derivative is either theta 00173 // or 1.0 in this implementation, but we scale the former part 00174 // ourselves 00175 context.elem_solution_derivative = 1.0; 00176 00177 // Technically the fixed_solution_derivative is always theta, 00178 // but we're scaling a whole jacobian by theta after these first 00179 // evaluations 00180 context.fixed_solution_derivative = 1.0; 00181 00182 // If a fixed solution is requested, we'll use theta_solution 00183 if (_system.use_fixed_solution) 00184 context.elem_fixed_solution = theta_solution; 00185 00186 // Move theta_->elem_, elem_->theta_ 00187 context.elem_solution.swap(theta_solution); 00188 00189 // Move the mesh into place first if necessary 00190 context.elem_side_reinit(theta); 00191 00192 // We're going to compute just the change in elem_residual 00193 // (and possibly elem_jacobian), then add back the old values 00194 DenseVector<Number> old_elem_residual(context.elem_residual); 00195 DenseMatrix<Number> old_elem_jacobian; 00196 if (request_jacobian) 00197 { 00198 old_elem_jacobian = context.elem_jacobian; 00199 context.elem_jacobian.zero(); 00200 } 00201 context.elem_residual.zero(); 00202 00203 // Get the time derivative at t_theta 00204 bool jacobian_computed = 00205 _system.side_time_derivative(request_jacobian, context); 00206 00207 // Scale the time-dependent residual and jacobian correctly 00208 context.elem_residual *= _system.deltat; 00209 if (jacobian_computed) 00210 context.elem_jacobian *= (theta * _system.deltat); 00211 00212 // The fixed_solution_derivative is always theta, 00213 // and now we're done scaling jacobians 00214 context.fixed_solution_derivative = theta; 00215 00216 // We evaluate side_mass_residual with the change in solution 00217 // to get the mass matrix, reusing old_elem_solution to hold that 00218 // delta_solution. We're solving dt*F(u) - du = 0, so our 00219 // delta_solution is old_solution - new_solution. 00220 // We're still keeping elem_solution in theta_solution for now 00221 old_elem_solution -= theta_solution; 00222 00223 // Move old_->elem_, theta_->old_ 00224 context.elem_solution.swap(old_elem_solution); 00225 00226 // We do a trick here to avoid using a non-1 00227 // elem_solution_derivative: 00228 context.elem_jacobian *= -1.0; 00229 jacobian_computed = _system.side_mass_residual(jacobian_computed, context) && 00230 jacobian_computed; 00231 context.elem_jacobian *= -1.0; 00232 00233 // Move elem_->elem_, old_->theta_ 00234 context.elem_solution.swap(theta_solution); 00235 00236 // Restore the elem position if necessary 00237 context.elem_side_reinit(1.); 00238 00239 // Add the constraint term 00240 jacobian_computed = _system.side_constraint(jacobian_computed, context) && 00241 jacobian_computed; 00242 00243 // Add back the old residual and jacobian 00244 context.elem_residual += old_elem_residual; 00245 if (request_jacobian) 00246 { 00247 if (jacobian_computed) 00248 context.elem_jacobian += old_elem_jacobian; 00249 else 00250 context.elem_jacobian.swap(old_elem_jacobian); 00251 } 00252 00253 return jacobian_computed; 00254 } 00255 00256 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:46 UTC
Hosted By: