$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 00020 #ifndef LIBMESH_SYSTEM_NORM_H 00021 #define LIBMESH_SYSTEM_NORM_H 00022 00023 // Local includes 00024 #include "libmesh/libmesh_common.h" // for Real 00025 #include "libmesh/enum_norm_type.h" 00026 00027 // C++ includes 00028 #include <vector> 00029 00030 namespace libMesh 00031 { 00032 00033 // Forward Declarations 00034 00045 // ------------------------------------------------------------ 00046 // SystemNorm class definition 00047 class SystemNorm 00048 { 00049 public: 00050 00054 SystemNorm(); 00055 00064 SystemNorm(const FEMNormType &t); 00065 00073 explicit 00074 SystemNorm(const std::vector<FEMNormType> &norms); 00075 00083 SystemNorm(const std::vector<FEMNormType> &norms, std::vector<Real> &weights); 00084 00092 SystemNorm(const std::vector<FEMNormType> &norms, std::vector<std::vector<Real> > &weights); 00093 00097 SystemNorm(const SystemNorm &s); 00098 00102 bool is_discrete() const; 00103 00108 Real calculate_norm(const std::vector<Real>& v); 00109 00113 Real calculate_norm(const std::vector<Real>& v1, const std::vector<Real>& v2); 00114 00118 bool is_identity(); 00119 00123 FEMNormType type(unsigned int var) const; 00124 00128 void set_type(unsigned int var, const FEMNormType& t); 00129 00133 Real weight(unsigned int var) const; 00134 00138 void set_weight(unsigned int var, Real w); 00139 00143 void set_off_diagonal_weight(unsigned int i, unsigned int j, Real w); 00144 00149 Real weight_sq(unsigned int var) const; 00150 00151 00152 00153 private: 00154 std::vector<FEMNormType> _norms; 00155 00156 std::vector<Real> _weights; 00157 std::vector<Real> _weights_sq; 00158 00163 std::vector<std::vector<Real> > _off_diagonal_weights; 00164 }; 00165 00166 00167 00168 // ------------------------------------------------------------ 00169 // SystemNorm inline methods 00170 00171 inline 00172 SystemNorm::SystemNorm() : 00173 _norms(1, DISCRETE_L2), _weights(1, 1.0), _weights_sq(1, 1.0) 00174 { 00175 } 00176 00177 00178 inline 00179 SystemNorm::SystemNorm(const FEMNormType &t) : 00180 _norms(1, t), _weights(1, 1.0), _weights_sq(1, 1.0) 00181 { 00182 } 00183 00184 00185 inline 00186 SystemNorm::SystemNorm(const std::vector<FEMNormType> &norms) : 00187 _norms(norms), _weights(1, 1.0), _weights_sq(1, 1.0) 00188 { 00189 if (_norms.empty()) 00190 _norms.push_back(DISCRETE_L2); 00191 } 00192 00193 00194 inline 00195 SystemNorm::SystemNorm(const std::vector<FEMNormType> &norms, 00196 std::vector<Real> &weights) : 00197 _norms(norms), _weights(weights), _weights_sq(_weights.size(), 0.0) 00198 { 00199 if (_norms.empty()) 00200 _norms.push_back(DISCRETE_L2); 00201 00202 if (_weights.empty()) 00203 { 00204 _weights.push_back(1.0); 00205 _weights_sq.push_back(1.0); 00206 } 00207 else 00208 for (std::size_t i=0; i != _weights.size(); ++i) 00209 _weights_sq[i] = _weights[i] * _weights[i]; 00210 } 00211 00212 inline 00213 SystemNorm::SystemNorm(const std::vector<FEMNormType> &norms, 00214 std::vector<std::vector<Real> > &weights): 00215 _norms(norms), 00216 _weights(weights.size()), 00217 _weights_sq(weights.size()), 00218 _off_diagonal_weights(weights) 00219 { 00220 if(_norms.empty()) 00221 _norms.push_back(DISCRETE_L2); 00222 00223 if (_weights.empty()) 00224 { 00225 _weights.push_back(1.0); 00226 _weights_sq.push_back(1.0); 00227 } 00228 else 00229 { 00230 // Loop over the entries of the user provided matrix and store its entries in 00231 // the _off_diagonal_weights or _diagonal_weights 00232 for(std::size_t i=0; i!=_off_diagonal_weights.size(); ++i) 00233 { 00234 if(_off_diagonal_weights[i].size() > i) 00235 { 00236 _weights[i] = _off_diagonal_weights[i][i]; 00237 _off_diagonal_weights[i][i] = 0; 00238 } 00239 else 00240 _weights[i] = 1.0; 00241 } 00242 for (std::size_t i=0; i != _weights.size(); ++i) 00243 _weights_sq[i] = _weights[i] * _weights[i]; 00244 } 00245 } 00246 00247 inline 00248 SystemNorm::SystemNorm(const SystemNorm &s) : 00249 _norms(s._norms), _weights(s._weights), _weights_sq(s._weights_sq) 00250 { 00251 } 00252 00253 00254 inline 00255 bool SystemNorm::is_discrete() const 00256 { 00257 libmesh_assert (!_norms.empty()); 00258 00259 if (_norms[0] == DISCRETE_L1 || 00260 _norms[0] == DISCRETE_L2 || 00261 _norms[0] == DISCRETE_L_INF) 00262 return true; 00263 00264 return false; 00265 } 00266 00267 00268 inline 00269 FEMNormType SystemNorm::type(unsigned int var) const 00270 { 00271 libmesh_assert (!_norms.empty()); 00272 00273 std::size_t i = (var < _norms.size()) ? var : _norms.size() - 1; 00274 00275 return _norms[i]; 00276 } 00277 00278 00279 00280 inline 00281 void SystemNorm::set_type(unsigned int var, const FEMNormType &t) 00282 { 00283 libmesh_assert (!_norms.empty()); 00284 00285 if (var >= _norms.size()) 00286 _norms.resize(var+1, t); 00287 00288 _norms[var] = t; 00289 } 00290 00291 00292 inline 00293 Real SystemNorm::weight(unsigned int var) const 00294 { 00295 libmesh_assert (!_weights.empty()); 00296 00297 return (var < _weights.size()) ? _weights[var] : 1.0; 00298 } 00299 00300 00301 inline 00302 void SystemNorm::set_weight(unsigned int var, Real w) 00303 { 00304 libmesh_assert (!_weights.empty()); 00305 00306 if (var >= _weights.size()) 00307 { 00308 _weights.resize(var+1, 1.0); 00309 _weights_sq.resize(var+1, 1.0); 00310 } 00311 00312 _weights[var] = w; 00313 _weights_sq[var] = w*w; 00314 } 00315 00316 inline 00317 void SystemNorm::set_off_diagonal_weight(unsigned int i, unsigned int j, Real w) 00318 { 00319 libmesh_assert (!_weights.empty()); 00320 00321 if (i >= _off_diagonal_weights.size()) 00322 { 00323 _off_diagonal_weights.resize(i+1); 00324 } 00325 00326 if (j >= _off_diagonal_weights[i].size()) 00327 { 00328 _off_diagonal_weights[i].resize(j+1, 0.); 00329 } 00330 00331 _off_diagonal_weights[i][j] = w; 00332 00333 } 00334 00335 00336 inline 00337 Real SystemNorm::weight_sq(unsigned int var) const 00338 { 00339 libmesh_assert (!_weights_sq.empty()); 00340 00341 return (var < _weights_sq.size()) ? _weights_sq[var] : 1.0; 00342 } 00343 00344 00345 inline 00346 Real SystemNorm::calculate_norm(const std::vector<Real>& v1, const std::vector<Real>& v2) 00347 { 00348 // The vectors are assumed to both be vectors of the (same number 00349 // of) components 00350 std::size_t vsize = v1.size(); 00351 libmesh_assert_equal_to (vsize, v2.size()); 00352 00353 // We'll support implicitly defining weights, but if the user sets 00354 // more weights than he uses then something's probably wrong 00355 std::size_t diagsize = this->_weights.size(); 00356 libmesh_assert_greater_equal (vsize, diagsize); 00357 00358 // Initialize the variable val 00359 Real val = 0.; 00360 00361 // Loop over all the components of the system with explicit 00362 // weights 00363 for(std::size_t i = 0; i != diagsize; i++) 00364 { 00365 val += this->_weights[i] * v1[i] * v2[i]; 00366 } 00367 // Loop over all the components of the system with implicit 00368 // weights 00369 for(std::size_t i = diagsize; i < vsize; i++) 00370 { 00371 val += v1[i] * v2[i]; 00372 } 00373 00374 // Loop over the components of the system 00375 std::size_t nrows = this->_off_diagonal_weights.size(); 00376 libmesh_assert_less_equal (vsize, nrows); 00377 00378 for(std::size_t i = 0; i != nrows; i++) 00379 { 00380 std::size_t ncols = this->_off_diagonal_weights[i].size(); 00381 for(std::size_t j=0; j != ncols; j++) 00382 { 00383 // Note that the diagonal weights here were set to zero 00384 // in the constructor 00385 val += this->_off_diagonal_weights[i][j] * v1[i] * v2[j]; 00386 } 00387 } 00388 00389 return(val); 00390 } 00391 00392 inline 00393 Real SystemNorm::calculate_norm(const std::vector<Real>& v1) 00394 { 00395 return this->calculate_norm(v1,v1); 00396 } 00397 00398 inline 00399 bool SystemNorm::is_identity() 00400 { 00401 std::size_t nrows = this->_off_diagonal_weights.size(); 00402 00403 // If any of the off-diagonal elements is not 0, then we are in the non-identity case 00404 for(std::size_t i = 0; i != nrows; i++) 00405 { 00406 std::size_t ncols = this->_off_diagonal_weights[i].size(); 00407 for(std::size_t j = 0; j != ncols; j++) 00408 { 00409 if(_off_diagonal_weights[i][j] != 0) 00410 { 00411 return(false); 00412 } 00413 } 00414 } 00415 00416 // If any of the diagonal elements is not 1, then we are in the non-identity case 00417 nrows = this->_weights.size(); 00418 for(std::size_t i = 0; i != nrows; i++) 00419 if(_weights[i] != 1) 00420 return(false); 00421 00422 // If all the off-diagonals elements are 0, and diagonal elements 1, then we are in an identity case 00423 return(true); 00424 } 00425 00426 } // namespace libMesh 00427 00428 #endif // LIBMESH_SYSTEM_NORM_H