Skip to content

Commit 79800ac

Browse files
committed
added: parallel adaptive (multipatch) support
1 parent d520eb4 commit 79800ac

8 files changed

Lines changed: 184 additions & 17 deletions

File tree

Apps/HDF5toVTx/HDF5toVTx.C

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ bool readBasis (std::vector<ASMbase*>& result, const std::string& name,
8080
std::string out;
8181
hdf.readString(geom.str(),out);
8282
ptype = out.substr(0,10) == "# LRSPLINE" ? ASM::LRSpline : ASM::Spline;
83+
isLR = ptype == ASM::LRSpline;
8384
int gdim = 0;
8485
if (ptype == ASM::LRSpline)
8586
gdim = out.substr(11,7) == "SURFACE" ? 2 : 3;

src/ASM/ASMunstruct.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ namespace LR //! Utilities for LR-splines.
4747
IntVec elements; //!< 0-based indices of the elements to refine
4848
RealArray errors; //!< List of error indicators for the elements
4949
std::vector<IntVec> MLGN; //!< MLGN mapping to use for multipatch
50+
IntVec pMLGN; //!< Parallel MLGN mapping to use with MPI
5051

5152
//! \brief Default constructor.
5253
explicit RefineData(bool rs = false) : refShare(rs) {}

src/ASM/GlobalNodes.C

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
#include "GlobalNodes.h"
1515
#include "ASMunstruct.h"
16+
#include "SIMbase.h"
17+
#include "DomainDecomposition.h"
1618
#include "Utilities.h"
1719

1820

@@ -178,3 +180,80 @@ GlobalNodes::calcGlobalNodes(const GlobalNodes::LRSplineVec& pchs,
178180

179181
return result;
180182
}
183+
184+
185+
GlobalNodes::IntVec
186+
GlobalNodes::calcDDMapping(const GlobalNodes::LRSplineVec& pchs,
187+
const std::vector<GlobalNodes::IntVec>& MLGN,
188+
const SIMbase& sim, int& nNodes)
189+
{
190+
const ProcessAdm& adm = sim.getProcessAdm();
191+
192+
int minNode = 0;
193+
if (adm.getProcId() > 0)
194+
adm.receive(minNode, adm.getProcId()-1);
195+
196+
IntVec result(*std::max_element(MLGN.back().begin(), MLGN.back().end()) + 1);
197+
std::iota(result.begin(), result.end(), minNode);
198+
int maxNode = adm.getProcId() == 0 ? 0 : minNode;
199+
200+
std::map<int,int> old2new;
201+
for (const auto& it : adm.dd.ghostConnections) {
202+
int sidx = sim.getLocalPatchIndex(it.slave);
203+
if (sidx < 1)
204+
continue;
205+
206+
IntVec lNodes = GlobalNodes::getBoundaryNodes(*pchs[sidx-1], it.dim, it.sidx, 0);
207+
for (int& i : lNodes)
208+
i = result[MLGN[sidx-1][i]];
209+
210+
int nRecv;
211+
adm.receive(nRecv, adm.dd.getPatchOwner(it.master));
212+
if (nRecv =! lNodes.size()) {
213+
std::cerr <<"\n *** GlobalNodes::calcDDMapping(): "
214+
<<" Topology error, boundary size "
215+
<< nRecv << ", expected " << lNodes.size() << std::endl;
216+
return IntVec();
217+
}
218+
IntVec glbNodes(lNodes.size());
219+
adm.receive(glbNodes, adm.dd.getPatchOwner(it.master));
220+
for (size_t i = 0; i < lNodes.size(); ++i)
221+
old2new[lNodes[i]] = glbNodes[i];
222+
}
223+
224+
// remap ghost nodes
225+
for (auto& it : result)
226+
utl::renumber(it, old2new, false);
227+
228+
// remap rest of our nodes
229+
for (int i = 0; i < (int)result.size(); ++i)
230+
if (old2new.find(i + minNode) == old2new.end()) {
231+
std::map<int,int> old2new2;
232+
old2new2[i + minNode] = maxNode++;
233+
for (auto& it : result)
234+
utl::renumber(it, old2new2, false);
235+
}
236+
237+
if (adm.getProcId() < adm.getNoProcs()-1)
238+
adm.send(maxNode, adm.getProcId()+1);
239+
240+
for (const auto& it : adm.dd.ghostConnections) {
241+
int midx = sim.getLocalPatchIndex(it.master);
242+
if (midx < 1)
243+
continue;
244+
245+
IntVec glbNodes = GlobalNodes::getBoundaryNodes(*pchs[midx-1], it.dim,
246+
it.midx, it.orient);
247+
for (size_t i = 0; i < glbNodes.size(); ++i)
248+
glbNodes[i] = result[MLGN[midx-1][glbNodes[i]]];
249+
250+
adm.send(int(glbNodes.size()), adm.dd.getPatchOwner(it.slave));
251+
adm.send(glbNodes, adm.dd.getPatchOwner(it.slave));
252+
}
253+
254+
#ifdef HAVE_MPI
255+
nNodes = adm.allReduce(adm.getProcId() == adm.getNoProcs()-1 ? maxNode : 0, MPI_SUM);
256+
#endif
257+
258+
return result;
259+
}

src/ASM/GlobalNodes.h

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919

2020
#include <vector>
2121

22+
class DomainDecomposition;
23+
class ProcessAdm;
24+
class SIMbase;
25+
2226

2327
/*!
2428
\brief Class establishing global node numbers for unstructed FE models.
@@ -39,12 +43,22 @@ class GlobalNodes
3943
static IntVec getBoundaryNodes(const LR::LRSpline& lr,
4044
int dim, int lidx, int orient);
4145

42-
4346
//! \brief Calculate global node numbers for a FE model.
44-
//! \param pchs The spline patches in the model
47+
//! \param pchs The spline patches in the model
4548
//! \param interfaces The topological connections for the spline patches
4649
static std::vector<IntVec> calcGlobalNodes(const LRSplineVec& pchs,
4750
const InterfaceVec& interfaces);
51+
52+
//! \brief Calculate parallel global node numbers for a FE model.
53+
//! \param pchs The spline patches in the model
54+
//! \param MLGN Process-global node numbers
55+
//! \param sim The simulator holding patch owner information
56+
//! \param adm The parallel process administrator
57+
//! \param dd The domain decomposition holding ghost connections
58+
//! \param[out] nNodes Total number of nodes in the model
59+
static IntVec calcDDMapping(const LRSplineVec& pchs,
60+
const std::vector<GlobalNodes::IntVec>& MLGN,
61+
const SIMbase& sim, int& nNodes);
4862
};
4963

5064
#endif

src/ASM/LR/ASMu2D.C

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1994,10 +1994,17 @@ void ASMu2D::getBoundaryNodes (int lIndex, IntVec& nodes, int basis,
19941994
default: return;
19951995
}
19961996

1997-
if (nodes.empty())
1997+
if (nodes.empty()) {
19981998
nodes = this->getEdgeNodes(edge, basis, 0);
1999-
else {
1999+
if (!local)
2000+
for (int& node : nodes)
2001+
node = MLGN[node-1];
2002+
} else {
20002003
IntVec nodes2 = this->getEdgeNodes(edge, basis, 0);
2004+
if (!local)
2005+
for (int& node : nodes2)
2006+
node = MLGN[node-1];
2007+
20012008
nodes.insert(nodes.end(), nodes2.begin(), nodes2.end());
20022009
}
20032010

src/SIM/AdaptiveSIM.C

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,9 @@ bool AdaptiveSIM::adaptMesh (int iStep, std::streamsize outPrec)
311311
if (eNorm.cols() < 1 || gNorm[adaptor](adNorm) < errTol*refNorm) return false;
312312

313313
// Calculate row index in eNorm of the error norm to adapt based on
314-
size_t i, eRow = adNorm;
314+
size_t eRow = adNorm;
315315
NormBase* norm = model.getNormIntegrand();
316-
for (i = 0; i < adaptor; i++)
316+
for (size_t i = 0; i < adaptor; i++)
317317
eRow += norm->getNoFields(i+1);
318318
delete norm;
319319

@@ -363,10 +363,12 @@ bool AdaptiveSIM::adaptMesh (int iStep, std::streamsize outPrec)
363363
#ifdef HAS_LRSPLINE
364364
prm.MLGN = GlobalNodes::calcGlobalNodes(refBasis, model.getInterfaces());
365365
nNodes = *std::max_element(prm.MLGN.back().begin(), prm.MLGN.back().end()) + 1;
366+
if (model.getProcessAdm().getNoProcs() > 1)
367+
prm.pMLGN = GlobalNodes::calcDDMapping(refBasis, prm.MLGN, model, nNodes);
366368
#endif
367369
}
368370
errors.reserve(nNodes);
369-
for (i = 0; i < nNodes; i++)
371+
for (int i = 0; i < nNodes; i++)
370372
errors.push_back(DblIdx(0.0,i));
371373

372374
for (i = 0; i < errors.size(); i++)
@@ -378,18 +380,21 @@ bool AdaptiveSIM::adaptMesh (int iStep, std::streamsize outPrec)
378380

379381
// extract element norms for this patch
380382
Vector locNorm(patch->getNoElms());
381-
for (i = 1; i <= patch->getNoElms(); ++i)
383+
for (size_t i = 1; i <= patch->getNoElms(); ++i)
382384
locNorm(i) = eNorm(eRow, patch->getElmID(i));
383385

384386
// remap from geometry basis to refinement basis
385387
Vector locErr(patch->getNoRefineNodes());
386388
static_cast<ASMunstruct*>(patch)->remapErrors(locErr, locNorm);
387389

388390
// insert into global error array
389-
for (i = 0; i < locErr.size(); ++i)
390-
if (model.getNoPatches() > 1)
391-
errors[prm.MLGN[patch->idx][i]].first += locErr[i];
392-
else
391+
for (size_t i = 0; i < locErr.size(); ++i)
392+
if (model.getNoPatches() > 1) {
393+
if (prm.pMLGN.empty())
394+
errors[prm.MLGN[patch->idx][i]].first += locErr[i];
395+
else
396+
errors[prm.pMLGN[prm.MLGN[patch->idx][i]]].first += locErr[i];
397+
} else
393398
errors[i].first += locErr[i];
394399
}
395400
}
@@ -400,10 +405,21 @@ bool AdaptiveSIM::adaptMesh (int iStep, std::streamsize outPrec)
400405
<<" is available for isotropic_function only."<< std::endl;
401406
return false;
402407
}
403-
for (i = 0; i < eNorm.cols(); i++)
408+
for (size_t i = 0; i < eNorm.cols(); i++)
404409
errors.push_back(DblIdx(eNorm(eRow,1+i),i));
405410
}
406411

412+
#ifdef HAVE_MPI
413+
std::vector<double> perr(errors.size(), 0.0);
414+
if (model.getProcessAdm().getNoProcs() > 1) {
415+
for (size_t i = 0; i < errors.size(); ++i)
416+
perr[i] = errors[i].first;
417+
model.getProcessAdm().allReduce(perr, MPI_SUM);
418+
for (size_t i = 0; i < errors.size(); ++i)
419+
errors[i].first = perr[i];
420+
}
421+
#endif
422+
407423
// Sort the elements in the sequence of decreasing errors
408424
std::sort(errors.begin(),errors.end(),std::greater<DblIdx>());
409425

@@ -468,8 +484,15 @@ bool AdaptiveSIM::adaptMesh (int iStep, std::streamsize outPrec)
468484
return false;
469485

470486
prm.elements.reserve(refineSize);
471-
for (i = 0; i < refineSize; i++)
472-
prm.elements.push_back(errors[i].second);
487+
for (size_t i = 0; i < refineSize; i++)
488+
if (prm.pMLGN.empty())
489+
prm.elements.push_back(errors[i].second);
490+
else {
491+
auto it = std::find(prm.pMLGN.begin(),
492+
prm.pMLGN.end(), errors[i].second);
493+
if (it != prm.pMLGN.end())
494+
prm.elements.push_back(it-prm.pMLGN.begin());
495+
}
473496

474497
// Now refine the mesh
475498
if (!storeMesh)

src/SIM/SIMbase.C

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,6 @@ void SIMbase::clearProperties ()
9999
for (auto& i4 : myTracs)
100100
delete i4.second;
101101

102-
myPatches.clear();
103102
myGlb2Loc.clear();
104103
myScalars.clear();
105104
myVectors.clear();

src/SIM/SIMinput.C

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1124,7 +1124,7 @@ bool SIMinput::refine (const LR::RefineData& prm,
11241124
}
11251125

11261126
// Single patch models only pass refinement call to the ASM level
1127-
if (myModel.size() == 1)
1127+
if (this->getNoPatches() == 1)
11281128
return (isRefined = pch->refine(prm,sol,fName));
11291129

11301130
if (!prm.errors.empty()) // refinement by true_beta
@@ -1196,6 +1196,49 @@ bool SIMinput::refine (const LR::RefineData& prm,
11961196
}
11971197
}
11981198

1199+
#ifdef HAVE_MPI
1200+
if (this->adm.getNoProcs() > 1) {
1201+
for (int i = 0; i < this->adm.getNoProcs(); ++i) {
1202+
int send = 0;
1203+
if (i == this->adm.getProcId())
1204+
for (auto& it : conformingIndices)
1205+
send += it.size();
1206+
1207+
int nRecv = adm.allReduce(send, MPI_SUM);
1208+
std::vector<int> vRecv;
1209+
if (i == this->adm.getProcId()) {
1210+
std::vector<int> vSend;
1211+
vRecv.reserve(nRecv);
1212+
for (auto& it : conformingIndices)
1213+
for (const int& node : it)
1214+
vRecv.push_back(prm.pMLGN[node]);
1215+
} else
1216+
vRecv.resize(nRecv);
1217+
1218+
MPI_Bcast(vRecv.data(), vRecv.size(), MPI_INT, i, *this->adm.getCommunicator());
1219+
1220+
if (i != this->adm.getProcId()) {
1221+
for (int& node : vRecv) {
1222+
auto it = std::find(prm.pMLGN.begin(), prm.pMLGN.end(), node);
1223+
if (it != prm.pMLGN.end()) {
1224+
int globId = it - prm.pMLGN.begin();
1225+
int locId;
1226+
for (size_t j = 0; j < myModel.size(); j++)
1227+
if (prm.MLGN.empty()) {
1228+
if ((locId = myModel[j]->getNodeIndex(globId)) > 0)
1229+
conformingIndices[j].insert(locId-1);
1230+
} else {
1231+
auto it = std::find(prm.MLGN[j].begin(), prm.MLGN[j].end(), globId);
1232+
if (it != prm.MLGN[j].end())
1233+
conformingIndices[j].insert(it-prm.MLGN[j].begin());
1234+
}
1235+
}
1236+
}
1237+
}
1238+
}
1239+
}
1240+
#endif
1241+
11991242
Vectors lsols;
12001243
lsols.reserve(sol.size()*myModel.size());
12011244
for (size_t i = 0; i < myModel.size(); i++)

0 commit comments

Comments
 (0)