MFEM v2.0
pfespace.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 #ifdef MFEM_USE_MPI
00013 
00014 #include "fem.hpp"
00015 #include "../general/sort_pairs.hpp"
00016 
00017 ParFiniteElementSpace::ParFiniteElementSpace(ParFiniteElementSpace &pf)
00018    : FiniteElementSpace(pf)
00019 {
00020    MyComm = pf.MyComm;
00021    NRanks = pf.NRanks;
00022    MyRank = pf.MyRank;
00023    pmesh = pf.pmesh;
00024    gcomm = pf.gcomm;
00025    pf.gcomm = NULL;
00026    ltdof_size = pf.ltdof_size;
00027    Swap(ldof_group, pf.ldof_group);
00028    Swap(ldof_ltdof, pf.ldof_ltdof);
00029    Swap(dof_offsets, pf.dof_offsets);
00030    Swap(tdof_offsets, pf.tdof_offsets);
00031    Swap(tdof_nb_offsets, pf.tdof_nb_offsets);
00032    Swap(ldof_sign, pf.ldof_sign);
00033    P = pf.P;
00034    pf.P = NULL;
00035 }
00036 
00037 ParFiniteElementSpace::ParFiniteElementSpace(
00038    ParMesh *pm, FiniteElementCollection *f, int dim, int order)
00039    : FiniteElementSpace(pm, f, dim, order)
00040 {
00041    mesh = pmesh = pm;
00042 
00043    MyComm = pmesh->GetComm();
00044    MPI_Comm_size(MyComm, &NRanks);
00045    MPI_Comm_rank(MyComm, &MyRank);
00046 
00047    P = NULL;
00048 
00049    if (NURBSext)
00050    {
00051       if (own_ext)
00052       {
00053          // the FiniteElementSpace constructor created a serial
00054          // NURBSExtension of higher order than the mesh NURBSExtension
00055 
00056          ParNURBSExtension *pNe = new ParNURBSExtension(
00057             NURBSext, dynamic_cast<ParNURBSExtension *>(pmesh->NURBSext));
00058          // serial NURBSext is destroyed by the above constructor
00059          NURBSext = pNe;
00060          UpdateNURBS();
00061       }
00062 
00063       ConstructTrueNURBSDofs();
00064    }
00065    else
00066    {
00067       ConstructTrueDofs();
00068    }
00069 
00070    GenerateGlobalOffsets();
00071 }
00072 
00073 void ParFiniteElementSpace::GetGroupComm(
00074    GroupCommunicator &gc, int ldof_type, Array<int> *ldof_sign)
00075 {
00076    int gr;
00077    int ng = pmesh->GetNGroups();
00078    int nvd, ned, nfd;
00079    Array<int> dofs;
00080 
00081    int group_ldof_counter;
00082    Table &group_ldof = gc.GroupLDofTable();
00083 
00084    nvd = fec->DofForGeometry(Geometry::POINT);
00085    ned = fec->DofForGeometry(Geometry::SEGMENT);
00086    nfd = (fdofs) ? (fdofs[1]-fdofs[0]) : (0);
00087 
00088    if (ldof_sign)
00089    {
00090       ldof_sign->SetSize(GetNDofs());
00091       *ldof_sign = 1;
00092    }
00093 
00094    // count the number of ldofs in all groups (excluding the local group 0)
00095    group_ldof_counter = 0;
00096    for (gr = 1; gr < ng; gr++)
00097    {
00098       group_ldof_counter += nvd * pmesh->GroupNVertices(gr);
00099       group_ldof_counter += ned * pmesh->GroupNEdges(gr);
00100       group_ldof_counter += nfd * pmesh->GroupNFaces(gr);
00101    }
00102    if (ldof_type)
00103       group_ldof_counter *= vdim;
00104    // allocate the I and J arrays in group_ldof
00105    group_ldof.SetDims(ng, group_ldof_counter);
00106 
00107    // build the full group_ldof table
00108    group_ldof_counter = 0;
00109    group_ldof.GetI()[0] = group_ldof.GetI()[1] = 0;
00110    for (gr = 1; gr < ng; gr++)
00111    {
00112       int j, k, l, m, o, nv, ne, nf;
00113       const int *ind;
00114 
00115       nv = pmesh->GroupNVertices(gr);
00116       ne = pmesh->GroupNEdges(gr);
00117       nf = pmesh->GroupNFaces(gr);
00118 
00119       // vertices
00120       if (nvd > 0)
00121          for (j = 0; j < nv; j++)
00122          {
00123             k = pmesh->GroupVertex(gr, j);
00124 
00125             dofs.SetSize(nvd);
00126             m = nvd * k;
00127             for (l = 0; l < nvd; l++, m++)
00128                dofs[l] = m;
00129 
00130             if (ldof_type)
00131                DofsToVDofs(dofs);
00132 
00133             for (l = 0; l < dofs.Size(); l++)
00134                group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
00135          }
00136 
00137       // edges
00138       if (ned > 0)
00139          for (j = 0; j < ne; j++)
00140          {
00141             pmesh->GroupEdge(gr, j, k, o);
00142 
00143             dofs.SetSize(ned);
00144             m = nvdofs+k*ned;
00145             ind = fec->DofOrderForOrientation(Geometry::SEGMENT, o);
00146             for (l = 0; l < ned; l++)
00147                if (ind[l] < 0)
00148                {
00149                   dofs[l] = m + (-1-ind[l]);
00150                   if (ldof_sign)
00151                      (*ldof_sign)[dofs[l]] = -1;
00152                }
00153                else
00154                   dofs[l] = m + ind[l];
00155 
00156             if (ldof_type)
00157                DofsToVDofs(dofs);
00158 
00159             for (l = 0; l < dofs.Size(); l++)
00160                group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
00161          }
00162 
00163       // faces
00164       if (nfd > 0)
00165          for (j = 0; j < nf; j++)
00166          {
00167             pmesh->GroupFace(gr, j, k, o);
00168 
00169             dofs.SetSize(nfd);
00170             m = nvdofs+nedofs+fdofs[k];
00171             ind = fec->DofOrderForOrientation(
00172                mesh->GetFaceBaseGeometry(k), o);
00173             for (l = 0; l < nfd; l++)
00174                if (ind[l] < 0)
00175                {
00176                   dofs[l] = m + (-1-ind[l]);
00177                   if (ldof_sign)
00178                      (*ldof_sign)[dofs[l]] = -1;
00179                }
00180                else
00181                   dofs[l] = m + ind[l];
00182 
00183             if (ldof_type)
00184                DofsToVDofs(dofs);
00185 
00186             for (l = 0; l < dofs.Size(); l++)
00187                group_ldof.GetJ()[group_ldof_counter++] = dofs[l];
00188          }
00189 
00190       group_ldof.GetI()[gr+1] = group_ldof_counter;
00191    }
00192 
00193    gc.Finalize();
00194 }
00195 
00196 void ParFiniteElementSpace::GetElementDofs(int i, Array<int> &dofs) const
00197 {
00198    if (elem_dof)
00199    {
00200       elem_dof->GetRow(i, dofs);
00201       return;
00202    }
00203    FiniteElementSpace::GetElementDofs(i, dofs);
00204    for (i = 0; i < dofs.Size(); i++)
00205       if (dofs[i] < 0)
00206       {
00207          if (ldof_sign[-1-dofs[i]] < 0)
00208             dofs[i] = -1-dofs[i];
00209       }
00210       else
00211       {
00212          if (ldof_sign[dofs[i]] < 0)
00213             dofs[i] = -1-dofs[i];
00214       }
00215 }
00216 
00217 void ParFiniteElementSpace::GetBdrElementDofs(int i, Array<int> &dofs) const
00218 {
00219    if (bdrElem_dof)
00220    {
00221       bdrElem_dof->GetRow(i, dofs);
00222       return;
00223    }
00224    FiniteElementSpace::GetBdrElementDofs(i, dofs);
00225    for (i = 0; i < dofs.Size(); i++)
00226       if (dofs[i] < 0)
00227       {
00228          if (ldof_sign[-1-dofs[i]] < 0)
00229             dofs[i] = -1-dofs[i];
00230       }
00231       else
00232       {
00233          if (ldof_sign[dofs[i]] < 0)
00234             dofs[i] = -1-dofs[i];
00235       }
00236 }
00237 
00238 void ParFiniteElementSpace::GenerateGlobalOffsets()
00239 {
00240    if (HYPRE_AssumedPartitionCheck())
00241    {
00242       int ldof[2];
00243 
00244       ldof[0] = GetVSize();
00245       ldof[1] = TrueVSize();
00246 
00247       dof_offsets.SetSize(3);
00248       tdof_offsets.SetSize(3);
00249 
00250       MPI_Scan(&ldof, &dof_offsets[0], 2, MPI_INT, MPI_SUM, MyComm);
00251 
00252       tdof_offsets[1] = dof_offsets[1];
00253       tdof_offsets[0] = tdof_offsets[1] - ldof[1];
00254 
00255       dof_offsets[1] = dof_offsets[0];
00256       dof_offsets[0] = dof_offsets[1] - ldof[0];
00257 
00258       // get the global sizes in (t)dof_offsets[2]
00259       if (MyRank == NRanks-1)
00260       {
00261          ldof[0] = dof_offsets[1];
00262          ldof[1] = tdof_offsets[1];
00263       }
00264 
00265       MPI_Bcast(&ldof, 2, MPI_INT, NRanks-1, MyComm);
00266       dof_offsets[2] = ldof[0];
00267       tdof_offsets[2] = ldof[1];
00268    }
00269    else
00270    {
00271       int i;
00272       int ldof  = GetVSize();
00273       int ltdof = TrueVSize();
00274 
00275       dof_offsets.SetSize (NRanks+1);
00276       tdof_offsets.SetSize(NRanks+1);
00277 
00278       MPI_Allgather(&ldof, 1, MPI_INT, &dof_offsets[1], 1, MPI_INT, MyComm);
00279       MPI_Allgather(&ltdof, 1, MPI_INT, &tdof_offsets[1], 1, MPI_INT, MyComm);
00280 
00281       dof_offsets[0] = tdof_offsets[0] = 0;
00282       for (i = 1; i < NRanks; i++)
00283       {
00284          dof_offsets [i+1] += dof_offsets [i];
00285          tdof_offsets[i+1] += tdof_offsets[i];
00286       }
00287    }
00288 }
00289 
00290 HypreParMatrix *ParFiniteElementSpace::Dof_TrueDof_Matrix() // matrix P
00291 {
00292    int  i;
00293 
00294    if (P)
00295       return P;
00296 
00297    int  ldof = GetVSize();
00298    int  ltdof = TrueVSize();
00299 
00300    GroupTopology &gt = GetGroupTopo();
00301 
00302    int *i_diag;
00303    int *j_diag;
00304    int  diag_counter;
00305 
00306    int *i_offd;
00307    int *j_offd;
00308    int  offd_counter;
00309 
00310    int *cmap;
00311    int *col_starts;
00312    int *row_starts;
00313 
00314    col_starts = GetTrueDofOffsets();
00315    row_starts = GetDofOffsets();
00316 
00317    i_diag = hypre_TAlloc(HYPRE_Int, ldof+1);
00318    j_diag = hypre_TAlloc(HYPRE_Int, ltdof);
00319 
00320    i_offd = hypre_TAlloc(HYPRE_Int, ldof+1);
00321    j_offd = hypre_TAlloc(HYPRE_Int, ldof-ltdof);
00322 
00323    cmap   = hypre_TAlloc(HYPRE_Int, ldof-ltdof);
00324 
00325    Array<Pair<int, int> > cmap_j_offd(ldof-ltdof);
00326 
00327    if (HYPRE_AssumedPartitionCheck())
00328    {
00329       int nsize = gt.GetNumNeighbors()-1;
00330       MPI_Request *requests = new MPI_Request[2*nsize];
00331       MPI_Status  *statuses = new MPI_Status[2*nsize];
00332       tdof_nb_offsets.SetSize(nsize+1);
00333       tdof_nb_offsets[0] = col_starts[0];
00334 
00335       int request_counter = 0;
00336       // send and receive neighbors' local tdof offsets
00337       for (i = 1; i <= nsize; i++)
00338          MPI_Irecv(&tdof_nb_offsets[i], 1, MPI_INT, gt.GetNeighborRank(i), 5365,
00339                    MyComm, &requests[request_counter++]);
00340 
00341       for (i = 1; i <= nsize; i++)
00342          MPI_Isend(&tdof_nb_offsets[0], 1, MPI_INT, gt.GetNeighborRank(i), 5365,
00343                    MyComm, &requests[request_counter++]);
00344 
00345       MPI_Waitall(request_counter, requests, statuses);
00346 
00347       delete [] statuses;
00348       delete [] requests;
00349    }
00350 
00351    i_diag[0] = i_offd[0] = 0;
00352    diag_counter = offd_counter = 0;
00353    for (i = 0; i < ldof; i++)
00354    {
00355       int proc = gt.GetGroupMasterRank(ldof_group[i]);
00356       if (proc == MyRank)
00357       {
00358          j_diag[diag_counter++] = ldof_ltdof[i];
00359       }
00360       else
00361       {
00362          if (HYPRE_AssumedPartitionCheck())
00363             cmap_j_offd[offd_counter].one =
00364                tdof_nb_offsets[gt.GetGroupMaster(ldof_group[i])] + ldof_ltdof[i];
00365          else
00366             cmap_j_offd[offd_counter].one = col_starts[proc] + ldof_ltdof[i];
00367          cmap_j_offd[offd_counter].two = offd_counter;
00368          offd_counter++;
00369       }
00370       i_diag[i+1] = diag_counter;
00371       i_offd[i+1] = offd_counter;
00372    }
00373 
00374    SortPairs<int, int>(cmap_j_offd, offd_counter);
00375 
00376    for (i = 0; i < offd_counter; i++)
00377    {
00378       cmap[i] = cmap_j_offd[i].one;
00379       j_offd[cmap_j_offd[i].two] = i;
00380    }
00381 
00382    P = new HypreParMatrix(MyComm, MyRank, NRanks, row_starts, col_starts,
00383                           i_diag, j_diag, i_offd, j_offd, cmap, offd_counter);
00384 
00385    return P;
00386 }
00387 
00388 void ParFiniteElementSpace::DivideByGroupSize(double *vec)
00389 {
00390    GroupTopology &gt = GetGroupTopo();
00391 
00392    for (int i = 0; i < ldof_group.Size(); i++)
00393       if (gt.IAmMaster(ldof_group[i])) // we are the master
00394          vec[ldof_ltdof[i]] /= gt.GetGroupSize(ldof_group[i]);
00395 }
00396 
00397 GroupCommunicator *ParFiniteElementSpace::ScalarGroupComm()
00398 {
00399    GroupCommunicator *gc = new GroupCommunicator(GetGroupTopo());
00400    if (NURBSext)
00401       gc->Create(pNURBSext()->ldof_group);
00402    else
00403       GetGroupComm(*gc, 0);
00404    return gc;
00405 }
00406 
00407 void ParFiniteElementSpace::Synchronize(Array<int> &ldof_marker)
00408 {
00409    if (ldof_marker.Size() != GetVSize())
00410       mfem_error("ParFiniteElementSpace::Synchronize");
00411 
00412    // implement allreduce(|) as reduce(|) + broadcast
00413    gcomm->Reduce(ldof_marker);
00414    gcomm->Bcast(ldof_marker);
00415 }
00416 
00417 void ParFiniteElementSpace::GetEssentialVDofs(Array<int> &bdr_attr_is_ess,
00418                                               Array<int> &ess_dofs)
00419 {
00420    FiniteElementSpace::GetEssentialVDofs(bdr_attr_is_ess, ess_dofs);
00421 
00422    // Make sure that processors without boundary elements mark
00423    // their boundary dofs (if they have any).
00424    Synchronize(ess_dofs);
00425 }
00426 
00427 int ParFiniteElementSpace::GetLocalTDofNumber(int ldof)
00428 {
00429    if (GetGroupTopo().IAmMaster(ldof_group[ldof]))
00430       return ldof_ltdof[ldof];
00431    else
00432       return -1;
00433 }
00434 
00435 int ParFiniteElementSpace::GetGlobalTDofNumber(int ldof)
00436 {
00437    if (HYPRE_AssumedPartitionCheck())
00438    {
00439       if (!P)
00440          Dof_TrueDof_Matrix();
00441       return ldof_ltdof[ldof] +
00442          tdof_nb_offsets[GetGroupTopo().GetGroupMaster(ldof_group[ldof])];
00443    }
00444 
00445    return ldof_ltdof[ldof] +
00446       tdof_offsets[GetGroupTopo().GetGroupMasterRank(ldof_group[ldof])];
00447 }
00448 
00449 int ParFiniteElementSpace::GetGlobalScalarTDofNumber(int sldof)
00450 {
00451    if (HYPRE_AssumedPartitionCheck())
00452    {
00453       if (!P)
00454          Dof_TrueDof_Matrix();
00455       if (ordering == Ordering::byNODES)
00456          return ldof_ltdof[sldof] +
00457             tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
00458                ldof_group[sldof])] / vdim;
00459       else
00460          return (ldof_ltdof[sldof*vdim] +
00461                  tdof_nb_offsets[GetGroupTopo().GetGroupMaster(
00462                        ldof_group[sldof*vdim])]) / vdim;
00463    }
00464 
00465    if (ordering == Ordering::byNODES)
00466       return ldof_ltdof[sldof] +
00467          tdof_offsets[GetGroupTopo().GetGroupMasterRank(
00468             ldof_group[sldof])] / vdim;
00469    else
00470       return (ldof_ltdof[sldof*vdim] +
00471               tdof_offsets[GetGroupTopo().GetGroupMasterRank(
00472                     ldof_group[sldof*vdim])]) / vdim;
00473 }
00474 
00475 void ParFiniteElementSpace::Lose_Dof_TrueDof_Matrix()
00476 {
00477    hypre_ParCSRMatrix *csrP = (hypre_ParCSRMatrix*)(*P);
00478    hypre_ParCSRMatrixOwnsRowStarts(csrP) = 1;
00479    hypre_ParCSRMatrixOwnsColStarts(csrP) = 1;
00480    P -> StealData();
00481    dof_offsets.LoseData();
00482    tdof_offsets.LoseData();
00483 }
00484 
00485 void ParFiniteElementSpace::ConstructTrueDofs()
00486 {
00487    int i, gr, n = GetVSize();
00488    GroupTopology &gt = pmesh->gtopo;
00489    gcomm = new GroupCommunicator(gt);
00490    Table &group_ldof = gcomm->GroupLDofTable();
00491 
00492    GetGroupComm(*gcomm, 1, &ldof_sign);
00493 
00494    // Define ldof_group and mark ldof_ltdof with
00495    //   -1 for ldof that is ours
00496    //   -2 for ldof that is in a group with another master
00497    ldof_group.SetSize(n);
00498    ldof_ltdof.SetSize(n);
00499    ldof_group = 0;
00500    ldof_ltdof = -1;
00501 
00502    for (gr = 1; gr < group_ldof.Size(); gr++)
00503    {
00504       const int *ldofs = group_ldof.GetRow(gr);
00505       const int nldofs = group_ldof.RowSize(gr);
00506       for (i = 0; i < nldofs; i++)
00507          ldof_group[ldofs[i]] = gr;
00508 
00509       if (!gt.IAmMaster(gr)) // we are not the master
00510          for (i = 0; i < nldofs; i++)
00511             ldof_ltdof[ldofs[i]] = -2;
00512    }
00513 
00514    // count ltdof_size
00515    ltdof_size = 0;
00516    for (i = 0; i < n; i++)
00517       if (ldof_ltdof[i] == -1)
00518          ldof_ltdof[i] = ltdof_size++;
00519 
00520    // have the group masters broadcast their ltdofs to the rest of the group
00521    gcomm->Bcast(ldof_ltdof);
00522 }
00523 
00524 void ParFiniteElementSpace::ConstructTrueNURBSDofs()
00525 {
00526    int n = GetVSize();
00527    GroupTopology &gt = pNURBSext()->gtopo;
00528    gcomm = new GroupCommunicator(gt);
00529 
00530    // pNURBSext()->ldof_group is for scalar space!
00531    if (vdim == 1)
00532    {
00533       ldof_group.MakeRef(pNURBSext()->ldof_group);
00534    }
00535    else
00536    {
00537       const int *scalar_ldof_group = pNURBSext()->ldof_group;
00538       ldof_group.SetSize(n);
00539       for (int i = 0; i < n; i++)
00540          ldof_group[i] = scalar_ldof_group[VDofToDof(i)];
00541    }
00542 
00543    gcomm->Create(ldof_group);
00544 
00545    // ldof_sign.SetSize(n);
00546    // ldof_sign = 1;
00547    ldof_sign.DeleteAll();
00548 
00549    ltdof_size = 0;
00550    ldof_ltdof.SetSize(n);
00551    for (int i = 0; i < n; i++)
00552    {
00553       if (gt.IAmMaster(ldof_group[i]))
00554       {
00555          ldof_ltdof[i] = ltdof_size;
00556          ltdof_size++;
00557       }
00558       else
00559       {
00560          ldof_ltdof[i] = -2;
00561       }
00562    }
00563 
00564    // have the group masters broadcast their ltdofs to the rest of the group
00565    gcomm->Bcast(ldof_ltdof);
00566 }
00567 
00568 void ParFiniteElementSpace::Update()
00569 {
00570    FiniteElementSpace::Update();
00571 
00572    ldof_group.DeleteAll();
00573    ldof_ltdof.DeleteAll();
00574    dof_offsets.DeleteAll();
00575    tdof_offsets.DeleteAll();
00576    tdof_nb_offsets.DeleteAll();
00577    ldof_sign.DeleteAll();
00578    delete P;
00579    P = NULL;
00580    delete gcomm;
00581    gcomm = NULL;
00582    ConstructTrueDofs();
00583    GenerateGlobalOffsets();
00584 }
00585 
00586 FiniteElementSpace *ParFiniteElementSpace::SaveUpdate()
00587 {
00588    ParFiniteElementSpace *cpfes = new ParFiniteElementSpace(*this);
00589    Constructor();
00590    ConstructTrueDofs();
00591    GenerateGlobalOffsets();
00592    return cpfes;
00593 }
00594 
00595 #endif
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines