MFEM v2.0
bilinearform.cpp
Go to the documentation of this file.
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 }
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines