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 #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(<dof, 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 > = 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 > = 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 > = 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 > = 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