$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 // C++ includes 00020 #include <iostream> 00021 #include <iomanip> 00022 #include <sstream> 00023 00024 // Local Includes 00025 #include "libmesh/adjoint_residual_error_estimator.h" 00026 #include "libmesh/error_vector.h" 00027 #include "libmesh/patch_recovery_error_estimator.h" 00028 #include "libmesh/libmesh_logging.h" 00029 #include "libmesh/numeric_vector.h" 00030 #include "libmesh/system.h" 00031 #include "libmesh/system_norm.h" 00032 #include "libmesh/qoi_set.h" 00033 00034 00035 namespace libMesh 00036 { 00037 00038 //----------------------------------------------------------------- 00039 // AdjointResidualErrorEstimator implementations 00040 AdjointResidualErrorEstimator::AdjointResidualErrorEstimator () : 00041 ErrorEstimator(), 00042 error_plot_suffix(), 00043 _primal_error_estimator(new PatchRecoveryErrorEstimator()), 00044 _dual_error_estimator(new PatchRecoveryErrorEstimator()), 00045 _qoi_set(QoISet()) 00046 { 00047 } 00048 00049 00050 00051 void AdjointResidualErrorEstimator::estimate_error (const System& _system, 00052 ErrorVector& error_per_cell, 00053 const NumericVector<Number>* solution_vector, 00054 bool estimate_parent_error) 00055 { 00056 START_LOG("estimate_error()", "AdjointResidualErrorEstimator"); 00057 00058 // The current mesh 00059 const MeshBase& mesh = _system.get_mesh(); 00060 00061 // Resize the error_per_cell vector to be 00062 // the number of elements, initialize it to 0. 00063 error_per_cell.resize (mesh.max_elem_id()); 00064 std::fill (error_per_cell.begin(), error_per_cell.end(), 0.); 00065 00066 // Get the number of variables in the system 00067 unsigned int n_vars = _system.n_vars(); 00068 00069 // We need to make a map of the pointer to the solution vector 00070 std::map<const System*, const NumericVector<Number>*>solutionvecs; 00071 solutionvecs[&_system] = _system.solution.get(); 00072 00073 // Solve the dual problem if we have to 00074 if (!_system.is_adjoint_already_solved()) 00075 { 00076 // FIXME - we'll need to change a lot of APIs to make this trick 00077 // work with a const System... 00078 System& system = const_cast<System&>(_system); 00079 system.adjoint_solve(_qoi_set); 00080 } 00081 00082 // Flag to check whether we have not been asked to weight the variable error contributions in any specific manner 00083 bool error_norm_is_identity = error_norm.is_identity(); 00084 00085 // Create an ErrorMap/ErrorVector to store the primal, dual and total_dual variable errors 00086 ErrorMap primal_errors_per_cell; 00087 ErrorMap dual_errors_per_cell; 00088 ErrorMap total_dual_errors_per_cell; 00089 // Allocate ErrorVectors to this map if we're going to use it 00090 if (!error_norm_is_identity) 00091 for(unsigned int v = 0; v < n_vars; v++) 00092 { 00093 primal_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector; 00094 dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector; 00095 total_dual_errors_per_cell[std::make_pair(&_system, v)] = new ErrorVector; 00096 } 00097 ErrorVector primal_error_per_cell; 00098 ErrorVector dual_error_per_cell; 00099 ErrorVector total_dual_error_per_cell; 00100 00101 // Have we been asked to weight the variable error contributions in any specific manner 00102 if(!error_norm_is_identity) // If we do 00103 { 00104 // Estimate the primal problem error for each variable 00105 _primal_error_estimator->estimate_errors 00106 (_system.get_equation_systems(), primal_errors_per_cell, &solutionvecs, estimate_parent_error); 00107 } 00108 else // If not 00109 { 00110 // Just get the combined error estimate 00111 _primal_error_estimator->estimate_error 00112 (_system, primal_error_per_cell, solution_vector, estimate_parent_error); 00113 } 00114 00115 // Sum and weight the dual error estimate based on our QoISet 00116 for (unsigned int i = 0; i != _system.qoi.size(); ++i) 00117 { 00118 if (_qoi_set.has_index(i)) 00119 { 00120 // Get the weight for the current QoI 00121 Real error_weight = _qoi_set.weight(i); 00122 00123 // We need to make a map of the pointer to the adjoint solution vector 00124 std::map<const System*, const NumericVector<Number>*>adjointsolutionvecs; 00125 adjointsolutionvecs[&_system] = &_system.get_adjoint_solution(i); 00126 00127 // Have we been asked to weight the variable error contributions in any specific manner 00128 if(!error_norm_is_identity) // If we have 00129 { 00130 _dual_error_estimator->estimate_errors 00131 (_system.get_equation_systems(), dual_errors_per_cell, &adjointsolutionvecs, 00132 estimate_parent_error); 00133 } 00134 else // If not 00135 { 00136 // Just get the combined error estimate 00137 _dual_error_estimator->estimate_error 00138 (_system, dual_error_per_cell, &(_system.get_adjoint_solution(i)), estimate_parent_error); 00139 } 00140 00141 std::size_t error_size; 00142 00143 // Get the size of the first ErrorMap vector; this will give us the number of elements 00144 if(!error_norm_is_identity) // If in non default weights case 00145 { 00146 error_size = dual_errors_per_cell[std::make_pair(&_system, 0)]->size(); 00147 } 00148 else // If in the standard default weights case 00149 { 00150 error_size = dual_error_per_cell.size(); 00151 } 00152 00153 // Resize the ErrorVector(s) 00154 if(!error_norm_is_identity) 00155 { 00156 // Loop over variables 00157 for(unsigned int v = 0; v < n_vars; v++) 00158 { 00159 libmesh_assert(!total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() || 00160 total_dual_errors_per_cell[std::make_pair(&_system, v)]->size() == error_size) ; 00161 total_dual_errors_per_cell[std::make_pair(&_system, v)]->resize(error_size); 00162 } 00163 } 00164 else 00165 { 00166 libmesh_assert(!total_dual_error_per_cell.size() || 00167 total_dual_error_per_cell.size() == error_size); 00168 total_dual_error_per_cell.resize(error_size); 00169 } 00170 00171 for (std::size_t e = 0; e != error_size; ++e) 00172 { 00173 // Have we been asked to weight the variable error contributions in any specific manner 00174 if(!error_norm_is_identity) // If we have 00175 { 00176 // Loop over variables 00177 for(unsigned int v = 0; v < n_vars; v++) 00178 { 00179 // Now fill in total_dual_error ErrorMap with the weight 00180 (*total_dual_errors_per_cell[std::make_pair(&_system, v)])[e] += 00181 static_cast<ErrorVectorReal> 00182 (error_weight * 00183 (*dual_errors_per_cell[std::make_pair(&_system, v)])[e]); 00184 } 00185 } 00186 else // If not 00187 { 00188 total_dual_error_per_cell[e] += 00189 static_cast<ErrorVectorReal>(error_weight * dual_error_per_cell[e]); 00190 } 00191 } 00192 } 00193 } 00194 00195 // Do some debugging plots if requested 00196 if (!error_plot_suffix.empty()) 00197 { 00198 if(!error_norm_is_identity) // If we have 00199 { 00200 // Loop over variables 00201 for(unsigned int v = 0; v < n_vars; v++) 00202 { 00203 std::ostringstream primal_out; 00204 std::ostringstream dual_out; 00205 primal_out << "primal_" << error_plot_suffix << "."; 00206 dual_out << "dual_" << error_plot_suffix << "."; 00207 00208 primal_out << std::setw(1) 00209 << std::setprecision(0) 00210 << std::setfill('0') 00211 << std::right 00212 << v; 00213 00214 dual_out << std::setw(1) 00215 << std::setprecision(0) 00216 << std::setfill('0') 00217 << std::right 00218 << v; 00219 00220 (*primal_errors_per_cell[std::make_pair(&_system, v)]).plot_error(primal_out.str(), _system.get_mesh()); 00221 (*total_dual_errors_per_cell[std::make_pair(&_system, v)]).plot_error(dual_out.str(), _system.get_mesh()); 00222 00223 primal_out.clear(); 00224 dual_out.clear(); 00225 } 00226 } 00227 else // If not 00228 { 00229 std::ostringstream primal_out; 00230 std::ostringstream dual_out; 00231 primal_out << "primal_" << error_plot_suffix ; 00232 dual_out << "dual_" << error_plot_suffix ; 00233 00234 primal_error_per_cell.plot_error(primal_out.str(), _system.get_mesh()); 00235 total_dual_error_per_cell.plot_error(dual_out.str(), _system.get_mesh()); 00236 00237 primal_out.clear(); 00238 dual_out.clear(); 00239 } 00240 } 00241 00242 // Weight the primal error by the dual error using the system norm object 00243 // FIXME: we ought to thread this 00244 for (unsigned int i=0; i != error_per_cell.size(); ++i) 00245 { 00246 // Have we been asked to weight the variable error contributions in any specific manner 00247 if(!error_norm_is_identity) // If we do 00248 { 00249 // Create Error Vectors to pass to calculate_norm 00250 std::vector<Real> cell_primal_error; 00251 std::vector<Real> cell_dual_error; 00252 00253 for(unsigned int v = 0; v < n_vars; v++) 00254 { 00255 cell_primal_error.push_back((*primal_errors_per_cell[std::make_pair(&_system, v)])[i]); 00256 cell_dual_error.push_back((*total_dual_errors_per_cell[std::make_pair(&_system, v)])[i]); 00257 } 00258 00259 error_per_cell[i] = 00260 static_cast<ErrorVectorReal> 00261 (error_norm.calculate_norm(cell_primal_error, cell_dual_error)); 00262 } 00263 else // If not 00264 { 00265 error_per_cell[i] = primal_error_per_cell[i]*total_dual_error_per_cell[i]; 00266 } 00267 } 00268 00269 // Deallocate the ErrorMap contents if we allocated them earlier 00270 if (!error_norm_is_identity) 00271 for(unsigned int v = 0; v < n_vars; v++) 00272 { 00273 delete primal_errors_per_cell[std::make_pair(&_system, v)]; 00274 delete dual_errors_per_cell[std::make_pair(&_system, v)]; 00275 delete total_dual_errors_per_cell[std::make_pair(&_system, v)]; 00276 } 00277 00278 STOP_LOG("estimate_error()", "AdjointResidualErrorEstimator"); 00279 } 00280 00281 } // namespace libMesh