linear_implicit_system.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 00020 // C++ includes 00021 00022 // Local includes 00023 #include "libmesh/linear_implicit_system.h" 00024 #include "libmesh/linear_solver.h" 00025 #include "libmesh/equation_systems.h" 00026 #include "libmesh/numeric_vector.h" // for parameter sensitivity calcs 00027 //#include "libmesh/parameter_vector.h" 00028 #include "libmesh/sparse_matrix.h" // for get_transpose 00029 #include "libmesh/system_subset.h" 00030 00031 namespace libMesh 00032 { 00033 00034 00035 // ------------------------------------------------------------ 00036 // LinearImplicitSystem implementation 00037 LinearImplicitSystem::LinearImplicitSystem (EquationSystems& es, 00038 const std::string& name_in, 00039 const unsigned int number_in) : 00040 00041 Parent (es, name_in, number_in), 00042 linear_solver (LinearSolver<Number>::build()), 00043 _n_linear_iterations (0), 00044 _final_linear_residual (1.e20), 00045 _shell_matrix(NULL), 00046 _subset(NULL), 00047 _subset_solve_mode(SUBSET_ZERO) 00048 { 00049 } 00050 00051 00052 00053 LinearImplicitSystem::~LinearImplicitSystem () 00054 { 00055 // Clear data 00056 this->clear(); 00057 } 00058 00059 00060 00061 void LinearImplicitSystem::clear () 00062 { 00063 // clear the linear solver 00064 linear_solver->clear(); 00065 00066 this->restrict_solve_to(NULL); 00067 00068 // clear the parent data 00069 Parent::clear(); 00070 } 00071 00072 00073 00074 void LinearImplicitSystem::init_data () 00075 { 00076 // initialize parent data 00077 Parent::init_data(); 00078 00079 // re-initialize the linear solver interface 00080 linear_solver->clear(); 00081 } 00082 00083 00084 00085 void LinearImplicitSystem::reinit () 00086 { 00087 // re-initialize the linear solver interface 00088 linear_solver->clear(); 00089 00090 // initialize parent data 00091 Parent::reinit(); 00092 } 00093 00094 00095 00096 void LinearImplicitSystem::restrict_solve_to (const SystemSubset* subset, 00097 const SubsetSolveMode subset_solve_mode) 00098 { 00099 _subset = subset; 00100 _subset_solve_mode = subset_solve_mode; 00101 if(subset!=NULL) 00102 { 00103 libmesh_assert_equal_to (&subset->get_system(), this); 00104 } 00105 } 00106 00107 00108 00109 void LinearImplicitSystem::solve () 00110 { 00111 if (this->assemble_before_solve) 00112 // Assemble the linear system 00113 this->assemble (); 00114 00115 // Log how long the linear solve takes. 00116 // This gets done by the LinearSolver classes now [RHS] 00117 // START_LOG("solve()", "System"); 00118 00119 // Get a reference to the EquationSystems 00120 const EquationSystems& es = 00121 this->get_equation_systems(); 00122 00123 // Get the user-specifiied linear solver tolerance 00124 const Real tol = 00125 es.parameters.get<Real>("linear solver tolerance"); 00126 00127 // Get the user-specified maximum # of linear solver iterations 00128 const unsigned int maxits = 00129 es.parameters.get<unsigned int>("linear solver maximum iterations"); 00130 00131 if(_subset!=NULL) 00132 { 00133 linear_solver->restrict_solve_to(&_subset->dof_ids(),_subset_solve_mode); 00134 } 00135 00136 // Solve the linear system. Several cases: 00137 std::pair<unsigned int, Real> rval = std::make_pair(0,0.0); 00138 if(_shell_matrix) 00139 // 1.) Shell matrix with or without user-supplied preconditioner. 00140 rval = linear_solver->solve(*_shell_matrix, this->request_matrix("Preconditioner"), *solution, *rhs, tol, maxits); 00141 else 00142 // 2.) No shell matrix, with or without user-supplied preconditioner 00143 rval = linear_solver->solve (*matrix, this->request_matrix("Preconditioner"), *solution, *rhs, tol, maxits); 00144 00145 if(_subset!=NULL) 00146 { 00147 linear_solver->restrict_solve_to(NULL); 00148 } 00149 00150 // Store the number of linear iterations required to 00151 // solve and the final residual. 00152 _n_linear_iterations = rval.first; 00153 _final_linear_residual = rval.second; 00154 00155 // Stop logging the linear solve 00156 // This gets done by the LinearSolver classes now [RHS] 00157 // STOP_LOG("solve()", "System"); 00158 00159 // Update the system after the solve 00160 this->update(); 00161 } 00162 00163 00164 00165 void LinearImplicitSystem::attach_shell_matrix (ShellMatrix<Number>* shell_matrix) 00166 { 00167 _shell_matrix = shell_matrix; 00168 } 00169 00170 00171 /* 00172 void LinearImplicitSystem::sensitivity_solve (const ParameterVector& parameters) 00173 { 00174 if (this->assemble_before_solve) 00175 { 00176 // Assemble the linear system 00177 this->assemble (); 00178 00179 // But now assemble right hand sides with the residual's 00180 // parameter derivatives 00181 this->assemble_residual_derivatives(parameters); 00182 } 00183 00184 // Get a reference to the EquationSystems 00185 const EquationSystems& es = 00186 this->get_equation_systems(); 00187 00188 // Get the user-specifiied linear solver tolerance 00189 const Real tol = 00190 es.parameters.get<Real>("sensitivity solver tolerance"); 00191 00192 // Get the user-specified maximum # of linear solver iterations 00193 const unsigned int maxits = 00194 es.parameters.get<unsigned int>("sensitivity solver maximum iterations"); 00195 00196 // Our iteration counts and residuals will be sums of the individual 00197 // results 00198 _n_linear_iterations = 0; 00199 _final_linear_residual = 0.0; 00200 std::pair<unsigned int, Real> rval = std::make_pair(0,0.0); 00201 00202 // Solve the linear system. 00203 SparseMatrix<Number> *pc = this->request_matrix("Preconditioner"); 00204 for (unsigned int p=0; p != parameters.size(); ++p) 00205 { 00206 rval = linear_solver->solve (*matrix, pc, 00207 this->get_sensitivity_solution(p), 00208 this->get_sensitivity_rhs(p), tol, maxits); 00209 _n_linear_iterations += rval.first; 00210 _final_linear_residual += rval.second; 00211 } 00212 00213 // Our matrix is the *negative* of the Jacobian for b-A*u, so our 00214 // solutions are all inverted 00215 for (unsigned int p=0; p != parameters.size(); ++p) 00216 { 00217 this->get_sensitivity_solution(p) *= -1.0; 00218 } 00219 } 00220 00221 00222 00223 void LinearImplicitSystem::adjoint_solve (const QoISet &qoi_indices) 00224 { 00225 const unsigned int Nq = this->qoi.size(); 00226 00227 // We currently don't support adjoint solves of shell matrices 00228 // FIXME - we should let shell matrices support 00229 // vector_transpose_mult so that we can use them here. 00230 if(_shell_matrix!=NULL) 00231 libmesh_not_implemented(); 00232 00233 if (this->assemble_before_solve) 00234 { 00235 // Assemble the linear system 00236 this->assemble (); 00237 00238 // And take the adjoint 00239 matrix->get_transpose(*matrix); 00240 00241 // Including of any separate preconditioner 00242 SparseMatrix<Number> *pc = this->request_matrix("Preconditioner"); 00243 if(pc) 00244 pc->get_transpose(*pc); 00245 00246 // But now replace the right hand sides with the quantity of 00247 // interest functional's derivative 00248 this->assemble_qoi_derivative(qoi_indices); 00249 } 00250 00251 // Get a reference to the EquationSystems 00252 const EquationSystems& es = 00253 this->get_equation_systems(); 00254 00255 // Get the user-specifiied linear solver tolerance 00256 const Real tol = 00257 es.parameters.get<Real>("adjoint solver tolerance"); 00258 00259 // Get the user-specified maximum # of linear solver iterations 00260 const unsigned int maxits = 00261 es.parameters.get<unsigned int>("adjoint solver maximum iterations"); 00262 00263 // Our iteration counts and residuals will be sums of the individual 00264 // results 00265 _n_linear_iterations = 0; 00266 _final_linear_residual = 0.0; 00267 std::pair<unsigned int, Real> rval = std::make_pair(0,0.0); 00268 00269 // Solve the linear system. 00270 SparseMatrix<Number> *pc = this->request_matrix("Preconditioner"); 00271 for (unsigned int i=0; i != Nq; ++i) 00272 if (qoi_indices.has_index(i)) 00273 { 00274 rval = linear_solver->solve (*matrix, pc, 00275 this->add_adjoint_solution(i), 00276 this->get_adjoint_rhs(i), tol, maxits); 00277 _n_linear_iterations += rval.first; 00278 _final_linear_residual += rval.second; 00279 } 00280 } 00281 00282 00283 00284 void LinearImplicitSystem::forward_qoi_parameter_sensitivity 00285 (const QoISet& qoi_indices, 00286 const ParameterVector& parameters, 00287 SensitivityData& sensitivities) 00288 { 00289 const unsigned int Np = parameters.size(); 00290 const unsigned int Nq = this->qoi.size(); 00291 00292 // An introduction to the problem: 00293 // 00294 // A(p)*u(p) = b(p), where x is determined implicitly. 00295 // Residual R(u(p),p) := b(p) - A(p)*u(p) 00296 // partial R / partial u = -A 00297 // 00298 // This implies that: 00299 // d/dp(R) = 0 00300 // (partial b / partial p) - 00301 // (partial A / partial p) * u - 00302 // A * (partial u / partial p) = 0 00303 // A * (partial u / partial p) = (partial R / partial p) 00304 // = (partial b / partial p) - (partial A / partial p) * u 00305 00306 // We first solve for (partial u / partial p) for each parameter: 00307 // -A * (partial u / partial p) = - (partial R / partial p) 00308 00309 this->sensitivity_solve(parameters); 00310 00311 // Get ready to fill in senstivities: 00312 sensitivities.allocate_data(qoi_indices, *this, parameters); 00313 00314 // We use the identity: 00315 // dq/dp = (partial q / partial p) + (partial q / partial u) * 00316 // (partial u / partial p) 00317 00318 // We get (partial q / partial u) from the user 00319 this->assemble_qoi_derivative(qoi_indices); 00320 00321 for (unsigned int j=0; j != Np; ++j) 00322 { 00323 // We currently get partial derivatives via central differencing 00324 Number delta_p = 1e-6; 00325 00326 // (partial q / partial p) ~= (q(p+dp)-q(p-dp))/(2*dp) 00327 00328 Number old_parameter = *parameters[j]; 00329 00330 *parameters[j] = old_parameter - delta_p; 00331 this->assemble_qoi(qoi_indices); 00332 std::vector<Number> qoi_minus = this->qoi; 00333 00334 *parameters[j] = old_parameter + delta_p; 00335 this->assemble_qoi(qoi_indices); 00336 std::vector<Number> &qoi_plus = this->qoi; 00337 std::vector<Number> partialq_partialp(Nq, 0); 00338 for (unsigned int i=0; i != Nq; ++i) 00339 if (qoi_indices.has_index(i)) 00340 partialq_partialp[i] = (qoi_plus[i] - qoi_minus[i]) / (2.*delta_p); 00341 00342 for (unsigned int i=0; i != Nq; ++i) 00343 if (qoi_indices.has_index(i)) 00344 sensitivities[i][j] = partialq_partialp[i] + 00345 this->get_adjoint_rhs(i).dot(this->get_sensitivity_solution(i)); 00346 } 00347 00348 // All parameters have been reset. 00349 // Don't leave the qoi or system changed - principle of least 00350 // surprise. 00351 this->assemble(); 00352 this->rhs->close(); 00353 this->matrix->close(); 00354 this->assemble_qoi(qoi_indices); 00355 } 00356 */ 00357 00358 00359 00360 LinearSolver<Number>* LinearImplicitSystem::get_linear_solver() const 00361 { 00362 return linear_solver.get(); 00363 } 00364 00365 00366 00367 void LinearImplicitSystem::release_linear_solver(LinearSolver<Number>*) const 00368 { 00369 } 00370 00371 00372 00373 void LinearImplicitSystem::assembly(bool, 00374 bool) 00375 { 00376 // Residual R(u(p),p) := A(p)*u(p) - b(p) 00377 // partial R / partial u = A 00378 00379 this->assemble(); 00380 this->rhs->close(); 00381 this->matrix->close(); 00382 00383 *(this->rhs) *= -1.0; 00384 this->rhs->add_vector(*this->solution, *this->matrix); 00385 } 00386 00387 } // namespace libMesh
Site Created By: libMesh Developers
Last modified: February 05 2013 19:54:47 UTC
Hosted By: