MFEM v2.0
|
00001 // Copyright (c) 2010, Lawrence Livermore National Security, LLC. Produced at 00002 // the Lawrence Livermore National Laboratory. LLNL-CODE-443211. All Rights 00003 // reserved. See file COPYRIGHT for details. 00004 // 00005 // This file is part of the MFEM library. For more information and source code 00006 // availability see http://mfem.googlecode.com. 00007 // 00008 // MFEM is free software; you can redistribute it and/or modify it under the 00009 // terms of the GNU Lesser General Public License (as published by the Free 00010 // Software Foundation) version 2.1 dated February 1999. 00011 00012 // Implementation of class BilinearForm 00013 00014 #include "fem.hpp" 00015 #include <math.h> 00016 00017 BilinearForm::BilinearForm (FiniteElementSpace * f) 00018 : Matrix (f->GetVSize()) 00019 { 00020 fes = f; 00021 mat = mat_e = NULL; 00022 extern_bfs = 0; 00023 element_matrices = NULL; 00024 } 00025 00026 BilinearForm::BilinearForm (FiniteElementSpace * f, BilinearForm * bf) 00027 : Matrix (f->GetVSize()) 00028 { 00029 int i; 00030 Array<BilinearFormIntegrator*> *bfi; 00031 00032 fes = f; 00033 mat = new SparseMatrix (size); 00034 mat_e = NULL; 00035 extern_bfs = 1; 00036 element_matrices = NULL; 00037 00038 bfi = bf->GetDBFI(); 00039 dbfi.SetSize (bfi->Size()); 00040 for (i = 0; i < bfi->Size(); i++) 00041 dbfi[i] = (*bfi)[i]; 00042 00043 bfi = bf->GetBBFI(); 00044 bbfi.SetSize (bfi->Size()); 00045 for (i = 0; i < bfi->Size(); i++) 00046 bbfi[i] = (*bfi)[i]; 00047 00048 bfi = bf->GetFBFI(); 00049 fbfi.SetSize (bfi->Size()); 00050 for (i = 0; i < bfi->Size(); i++) 00051 fbfi[i] = (*bfi)[i]; 00052 00053 bfi = bf->GetBFBFI(); 00054 bfbfi.SetSize (bfi->Size()); 00055 for (i = 0; i < bfi->Size(); i++) 00056 bfbfi[i] = (*bfi)[i]; 00057 } 00058 00059 double& BilinearForm::Elem (int i, int j) 00060 { 00061 return mat -> Elem(i,j); 00062 } 00063 00064 const double& BilinearForm::Elem (int i, int j) const 00065 { 00066 return mat -> Elem(i,j); 00067 } 00068 00069 void BilinearForm::Mult (const Vector & x, Vector & y) const 00070 { 00071 mat -> Mult (x, y); 00072 } 00073 00074 MatrixInverse * BilinearForm::Inverse() const 00075 { 00076 return mat -> Inverse(); 00077 } 00078 00079 void BilinearForm::Finalize (int skip_zeros) 00080 { 00081 mat -> Finalize (skip_zeros); 00082 if (mat_e) 00083 mat_e -> Finalize (skip_zeros); 00084 } 00085 00086 void BilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi) 00087 { 00088 dbfi.Append (bfi); 00089 } 00090 00091 void BilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi) 00092 { 00093 bbfi.Append (bfi); 00094 } 00095 00096 void BilinearForm::AddInteriorFaceIntegrator (BilinearFormIntegrator * bfi) 00097 { 00098 fbfi.Append (bfi); 00099 } 00100 00101 void BilinearForm::AddBdrFaceIntegrator (BilinearFormIntegrator * bfi) 00102 { 00103 bfbfi.Append (bfi); 00104 } 00105 00106 void BilinearForm::ComputeElementMatrix(int i, DenseMatrix &elmat) 00107 { 00108 if (element_matrices) 00109 { 00110 DenseMatrix tmp(element_matrices->GetData(i), 00111 element_matrices->SizeI(), 00112 element_matrices->SizeJ()); 00113 elmat = tmp; 00114 return; 00115 } 00116 00117 if (dbfi.Size()) 00118 { 00119 const FiniteElement &fe = *fes->GetFE(i); 00120 ElementTransformation *eltrans = fes->GetElementTransformation(i); 00121 dbfi[0]->AssembleElementMatrix(fe, *eltrans, elmat); 00122 for (int k = 1; k < dbfi.Size(); k++) 00123 { 00124 dbfi[k]->AssembleElementMatrix(fe, *eltrans, elemmat); 00125 elmat += elemmat; 00126 } 00127 } 00128 else 00129 { 00130 fes->GetElementVDofs(i, vdofs); 00131 elmat.SetSize(vdofs.Size()); 00132 elmat = 0.0; 00133 } 00134 } 00135 00136 void BilinearForm::AssembleElementMatrix( 00137 int i, const DenseMatrix &elmat, Array<int> &vdofs, int skip_zeros) 00138 { 00139 if (mat == NULL) 00140 mat = new SparseMatrix(size); 00141 fes->GetElementVDofs(i, vdofs); 00142 mat->AddSubMatrix(vdofs, vdofs, elmat, skip_zeros); 00143 } 00144 00145 void BilinearForm::Assemble (int skip_zeros) 00146 { 00147 ElementTransformation *eltrans; 00148 Mesh *mesh = fes -> GetMesh(); 00149 00150 int i; 00151 00152 if (mat == NULL) 00153 mat = new SparseMatrix(size); 00154 00155 #ifdef MFEM_USE_OPENMP 00156 int free_element_matrices = 0; 00157 if (!element_matrices) 00158 { 00159 ComputeElementMatrices(); 00160 free_element_matrices = 1; 00161 } 00162 #endif 00163 00164 if (dbfi.Size()) 00165 for (i = 0; i < fes -> GetNE(); i++) 00166 { 00167 fes->GetElementVDofs(i, vdofs); 00168 if (element_matrices) 00169 { 00170 mat->AddSubMatrix(vdofs, vdofs, (*element_matrices)(i), skip_zeros); 00171 } 00172 else 00173 { 00174 const FiniteElement &fe = *fes->GetFE(i); 00175 eltrans = fes->GetElementTransformation(i); 00176 for (int k = 0; k < dbfi.Size(); k++) 00177 { 00178 dbfi[k]->AssembleElementMatrix(fe, *eltrans, elemmat); 00179 mat->AddSubMatrix(vdofs, vdofs, elemmat, skip_zeros); 00180 } 00181 } 00182 } 00183 00184 if (bbfi.Size()) 00185 for (i = 0; i < fes -> GetNBE(); i++) 00186 { 00187 const FiniteElement &be = *fes->GetBE(i); 00188 fes -> GetBdrElementVDofs (i, vdofs); 00189 eltrans = fes -> GetBdrElementTransformation (i); 00190 for (int k=0; k < bbfi.Size(); k++) 00191 { 00192 bbfi[k] -> AssembleElementMatrix(be, *eltrans, elemmat); 00193 mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros); 00194 } 00195 } 00196 00197 if (fbfi.Size()) 00198 { 00199 FaceElementTransformations *tr; 00200 Array<int> vdofs2; 00201 00202 int nfaces; 00203 if (mesh -> Dimension() == 2) 00204 nfaces = mesh -> GetNEdges(); 00205 else 00206 nfaces = mesh -> GetNFaces(); 00207 for (i = 0; i < nfaces; i++) 00208 { 00209 tr = mesh -> GetInteriorFaceTransformations (i); 00210 if (tr != NULL) 00211 { 00212 fes -> GetElementVDofs (tr -> Elem1No, vdofs); 00213 fes -> GetElementVDofs (tr -> Elem2No, vdofs2); 00214 vdofs.Append (vdofs2); 00215 for (int k = 0; k < fbfi.Size(); k++) 00216 { 00217 fbfi[k] -> AssembleFaceMatrix (*fes -> GetFE (tr -> Elem1No), 00218 *fes -> GetFE (tr -> Elem2No), 00219 *tr, elemmat); 00220 mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros); 00221 } 00222 } 00223 } 00224 } 00225 00226 if (bfbfi.Size()) 00227 { 00228 FaceElementTransformations *tr; 00229 const FiniteElement *nfe = NULL; 00230 00231 for (i = 0; i < fes -> GetNBE(); i++) 00232 { 00233 tr = mesh -> GetBdrFaceTransformations (i); 00234 if (tr != NULL) 00235 { 00236 fes -> GetElementVDofs (tr -> Elem1No, vdofs); 00237 for (int k = 0; k < bfbfi.Size(); k++) 00238 { 00239 bfbfi[k] -> AssembleFaceMatrix (*fes -> GetFE (tr -> Elem1No), 00240 *nfe, *tr, elemmat); 00241 mat -> AddSubMatrix (vdofs, vdofs, elemmat, skip_zeros); 00242 } 00243 } 00244 } 00245 } 00246 00247 #ifdef MFEM_USE_OPENMP 00248 if (free_element_matrices) 00249 FreeElementMatrices(); 00250 #endif 00251 } 00252 00253 void BilinearForm::ComputeElementMatrices() 00254 { 00255 if (element_matrices || dbfi.Size() == 0) 00256 return; 00257 00258 int num_elements = fes->GetNE(); 00259 int num_dofs_per_el = fes->GetFE(0)->GetDof() * fes->GetVDim(); 00260 00261 element_matrices = new DenseTensor(num_dofs_per_el, num_dofs_per_el, 00262 num_elements); 00263 00264 DenseMatrix tmp; 00265 IsoparametricTransformation eltrans; 00266 00267 #ifdef MFEM_USE_OPENMP 00268 #pragma omp parallel for private(tmp,eltrans) 00269 #endif 00270 for (int i = 0; i < num_elements; i++) 00271 { 00272 DenseMatrix elmat(element_matrices->GetData(i), 00273 num_dofs_per_el, num_dofs_per_el); 00274 const FiniteElement &fe = *fes->GetFE(i); 00275 #ifdef MFEM_DEBUG 00276 if (num_dofs_per_el != fe.GetDof()*fes->GetVDim()) 00277 mfem_error("BilinearForm::ComputeElementMatrices:" 00278 " all elements must have same number of dofs"); 00279 #endif 00280 fes->GetElementTransformation(i, &eltrans); 00281 00282 dbfi[0]->AssembleElementMatrix(fe, eltrans, elmat); 00283 for (int k = 1; k < dbfi.Size(); k++) 00284 { 00285 // note: some integrators may not be thread-safe 00286 dbfi[k]->AssembleElementMatrix(fe, eltrans, tmp); 00287 elmat += tmp; 00288 } 00289 elmat.ClearExternalData(); 00290 } 00291 } 00292 00293 void BilinearForm::EliminateEssentialBC ( 00294 Array<int> &bdr_attr_is_ess, Vector &sol, Vector &rhs, int d ) 00295 { 00296 int i, j, k; 00297 00298 for (i = 0; i < fes -> GetNBE(); i++) 00299 if (bdr_attr_is_ess[fes -> GetBdrAttribute (i)-1]) 00300 { 00301 fes -> GetBdrElementVDofs (i, vdofs); 00302 for (j = 0; j < vdofs.Size(); j++) 00303 if ( (k = vdofs[j]) >= 0 ) 00304 mat -> EliminateRowCol (k, sol(k), rhs, d); 00305 else 00306 mat -> EliminateRowCol (-1-k, sol(-1-k), rhs, d); 00307 } 00308 } 00309 00310 void BilinearForm::EliminateVDofs ( 00311 Array<int> &vdofs, Vector &sol, Vector &rhs, int d) 00312 { 00313 for (int i = 0; i < vdofs.Size(); i++) 00314 { 00315 int vdof = vdofs[i]; 00316 if ( vdof >= 0 ) 00317 mat -> EliminateRowCol (vdof, sol(vdof), rhs, d); 00318 else 00319 mat -> EliminateRowCol (-1-vdof, sol(-1-vdof), rhs, d); 00320 } 00321 } 00322 00323 void BilinearForm::EliminateVDofs(Array<int> &vdofs, int d) 00324 { 00325 if (mat_e == NULL) 00326 mat_e = new SparseMatrix(size); 00327 00328 for (int i = 0; i < vdofs.Size(); i++) 00329 { 00330 int vdof = vdofs[i]; 00331 if ( vdof >= 0 ) 00332 mat -> EliminateRowCol (vdof, *mat_e, d); 00333 else 00334 mat -> EliminateRowCol (-1-vdof, *mat_e, d); 00335 } 00336 } 00337 00338 void BilinearForm::EliminateVDofsInRHS( 00339 Array<int> &vdofs, const Vector &x, Vector &b) 00340 { 00341 mat_e->AddMult(x, b, -1.); 00342 mat->PartMult(vdofs, x, b); 00343 } 00344 00345 void BilinearForm::EliminateEssentialBC (Array<int> &bdr_attr_is_ess, int d) 00346 { 00347 int i, j, k; 00348 Array<int> vdofs; 00349 00350 for (i = 0; i < fes -> GetNBE(); i++) 00351 if (bdr_attr_is_ess[fes -> GetBdrAttribute (i)-1]) 00352 { 00353 fes -> GetBdrElementVDofs (i, vdofs); 00354 for (j = 0; j < vdofs.Size(); j++) 00355 if ( (k = vdofs[j]) >= 0 ) 00356 mat -> EliminateRowCol (k, d); 00357 else 00358 mat -> EliminateRowCol (-1-k, d); 00359 } 00360 } 00361 00362 void BilinearForm::EliminateEssentialBCFromDofs ( 00363 Array<int> &ess_dofs, Vector &sol, Vector &rhs, int d ) 00364 { 00365 for (int i = 0; i < ess_dofs.Size(); i++) 00366 if (ess_dofs[i] < 0) 00367 mat -> EliminateRowCol (i, sol(i), rhs, d); 00368 } 00369 00370 void BilinearForm::EliminateEssentialBCFromDofs (Array<int> &ess_dofs, int d) 00371 { 00372 for (int i = 0; i < ess_dofs.Size(); i++) 00373 if (ess_dofs[i] < 0) 00374 mat -> EliminateRowCol (i, d); 00375 } 00376 00377 void BilinearForm::Update (FiniteElementSpace *nfes) 00378 { 00379 if (nfes) fes = nfes; 00380 00381 delete mat_e; 00382 delete mat; 00383 FreeElementMatrices(); 00384 00385 size = fes->GetVSize(); 00386 00387 mat = mat_e = NULL; 00388 } 00389 00390 BilinearForm::~BilinearForm() 00391 { 00392 delete mat_e; 00393 delete mat; 00394 delete element_matrices; 00395 00396 if (!extern_bfs) 00397 { 00398 int k; 00399 for (k=0; k < dbfi.Size(); k++) delete dbfi[k]; 00400 for (k=0; k < bbfi.Size(); k++) delete bbfi[k]; 00401 for (k=0; k < fbfi.Size(); k++) delete fbfi[k]; 00402 for (k=0; k < bfbfi.Size(); k++) delete bfbfi[k]; 00403 } 00404 } 00405 00406 00407 MixedBilinearForm::MixedBilinearForm (FiniteElementSpace *tr_fes, 00408 FiniteElementSpace *te_fes) 00409 : Matrix (te_fes->GetVSize()) 00410 { 00411 width = tr_fes->GetVSize(); 00412 trial_fes = tr_fes; 00413 test_fes = te_fes; 00414 mat = NULL; 00415 } 00416 00417 double & MixedBilinearForm::Elem (int i, int j) 00418 { 00419 return (*mat)(i, j); 00420 } 00421 00422 const double & MixedBilinearForm::Elem (int i, int j) const 00423 { 00424 return (*mat)(i, j); 00425 } 00426 00427 void MixedBilinearForm::Mult (const Vector & x, Vector & y) const 00428 { 00429 mat -> Mult (x, y); 00430 } 00431 00432 void MixedBilinearForm::AddMult (const Vector & x, Vector & y, 00433 const double a) const 00434 { 00435 mat -> AddMult (x, y, a); 00436 } 00437 00438 void MixedBilinearForm::AddMultTranspose (const Vector & x, Vector & y, 00439 const double a) const 00440 { 00441 mat -> AddMultTranspose (x, y, a); 00442 } 00443 00444 MatrixInverse * MixedBilinearForm::Inverse() const 00445 { 00446 return mat -> Inverse (); 00447 } 00448 00449 void MixedBilinearForm::Finalize (int skip_zeros) 00450 { 00451 mat -> Finalize (skip_zeros); 00452 } 00453 00454 void MixedBilinearForm::GetBlocks(Array2D<SparseMatrix *> &blocks) const 00455 { 00456 if (trial_fes->GetOrdering() != Ordering::byNODES || 00457 test_fes->GetOrdering() != Ordering::byNODES) 00458 mfem_error("MixedBilinearForm::GetBlocks :\n" 00459 " Both trial and test spaces must use Ordering::byNODES!"); 00460 00461 blocks.SetSize(test_fes->GetVDim(), trial_fes->GetVDim()); 00462 00463 mat->GetBlocks(blocks); 00464 } 00465 00466 void MixedBilinearForm::AddDomainIntegrator (BilinearFormIntegrator * bfi) 00467 { 00468 dom.Append (bfi); 00469 } 00470 00471 void MixedBilinearForm::AddBoundaryIntegrator (BilinearFormIntegrator * bfi) 00472 { 00473 bdr.Append (bfi); 00474 } 00475 00476 void MixedBilinearForm::Assemble (int skip_zeros) 00477 { 00478 int i, k; 00479 Array<int> tr_vdofs, te_vdofs; 00480 ElementTransformation *eltrans; 00481 DenseMatrix elemmat; 00482 00483 if (mat == NULL) 00484 mat = new SparseMatrix(size, width); 00485 00486 if (dom.Size()) 00487 for (i = 0; i < test_fes -> GetNE(); i++) 00488 { 00489 trial_fes -> GetElementVDofs (i, tr_vdofs); 00490 test_fes -> GetElementVDofs (i, te_vdofs); 00491 eltrans = test_fes -> GetElementTransformation (i); 00492 for (k = 0; k < dom.Size(); k++) 00493 { 00494 dom[k] -> AssembleElementMatrix2 (*trial_fes -> GetFE(i), 00495 *test_fes -> GetFE(i), 00496 *eltrans, elemmat); 00497 mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros); 00498 } 00499 } 00500 00501 if (bdr.Size()) 00502 for (i = 0; i < test_fes -> GetNBE(); i++) 00503 { 00504 trial_fes -> GetBdrElementVDofs (i, tr_vdofs); 00505 test_fes -> GetBdrElementVDofs (i, te_vdofs); 00506 eltrans = test_fes -> GetBdrElementTransformation (i); 00507 for (k = 0; k < bdr.Size(); k++) 00508 { 00509 bdr[k] -> AssembleElementMatrix2 (*trial_fes -> GetBE(i), 00510 *test_fes -> GetBE(i), 00511 *eltrans, elemmat); 00512 mat -> AddSubMatrix (te_vdofs, tr_vdofs, elemmat, skip_zeros); 00513 } 00514 } 00515 } 00516 00517 void MixedBilinearForm::EliminateTrialDofs ( 00518 Array<int> &bdr_attr_is_ess, Vector &sol, Vector &rhs ) 00519 { 00520 int i, j, k; 00521 Array<int> tr_vdofs, cols_marker (trial_fes -> GetVSize()); 00522 00523 cols_marker = 0; 00524 for (i = 0; i < trial_fes -> GetNBE(); i++) 00525 if (bdr_attr_is_ess[trial_fes -> GetBdrAttribute (i)-1]) 00526 { 00527 trial_fes -> GetBdrElementVDofs (i, tr_vdofs); 00528 for (j = 0; j < tr_vdofs.Size(); j++) 00529 { 00530 if ( (k = tr_vdofs[j]) < 0 ) 00531 k = -1-k; 00532 cols_marker[k] = 1; 00533 } 00534 } 00535 mat -> EliminateCols (cols_marker, &sol, &rhs); 00536 } 00537 00538 void MixedBilinearForm::EliminateTestDofs (Array<int> &bdr_attr_is_ess) 00539 { 00540 int i, j, k; 00541 Array<int> te_vdofs; 00542 00543 for (i = 0; i < test_fes -> GetNBE(); i++) 00544 if (bdr_attr_is_ess[test_fes -> GetBdrAttribute (i)-1]) 00545 { 00546 test_fes -> GetBdrElementVDofs (i, te_vdofs); 00547 for (j = 0; j < te_vdofs.Size(); j++) 00548 { 00549 if ( (k = te_vdofs[j]) < 0 ) 00550 k = -1-k; 00551 mat -> EliminateRow (k); 00552 } 00553 } 00554 } 00555 00556 void MixedBilinearForm::Update() 00557 { 00558 delete mat; 00559 mat = NULL; 00560 size = test_fes->GetVSize(); 00561 width = trial_fes->GetVSize(); 00562 } 00563 00564 MixedBilinearForm::~MixedBilinearForm() 00565 { 00566 int i; 00567 00568 if (mat) delete mat; 00569 for (i = 0; i < dom.Size(); i++) delete dom[i]; 00570 for (i = 0; i < bdr.Size(); i++) delete bdr[i]; 00571 } 00572 00573 00574 void DiscreteLinearOperator::Assemble(int skip_zeros) 00575 { 00576 Array<int> dom_vdofs, ran_vdofs; 00577 ElementTransformation *T; 00578 const FiniteElement *dom_fe, *ran_fe; 00579 DenseMatrix totelmat, elmat; 00580 00581 if (mat == NULL) 00582 mat = new SparseMatrix(size, width); 00583 00584 if (dom.Size() > 0) 00585 for (int i = 0; i < test_fes->GetNE(); i++) 00586 { 00587 trial_fes->GetElementVDofs(i, dom_vdofs); 00588 test_fes->GetElementVDofs(i, ran_vdofs); 00589 T = test_fes->GetElementTransformation(i); 00590 dom_fe = trial_fes->GetFE(i); 00591 ran_fe = test_fes->GetFE(i); 00592 00593 dom[0]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, totelmat); 00594 for (int j = 1; j < dom.Size(); j++) 00595 { 00596 dom[j]->AssembleElementMatrix2(*dom_fe, *ran_fe, *T, elmat); 00597 totelmat += elmat; 00598 } 00599 mat->SetSubMatrix(ran_vdofs, dom_vdofs, totelmat, skip_zeros); 00600 } 00601 }