Merge remote-tracking branch 'origin/master' into hughcars/nc-internal-bdr-project-fix

This commit is contained in:
Hugh Carson
2024-05-20 10:43:52 -04:00
12 changed files with 738 additions and 214 deletions
+21 -8
View File
@@ -53,6 +53,7 @@ jobs:
mpi: [seq, par]
build-system: [make, cmake]
hypre-target: [int32]
precision: [fp64]
exclude:
- os: ubuntu-latest
build-system: cmake
@@ -90,6 +91,7 @@ jobs:
mpi: par
build-system: cmake
hypre-target: int32
precision: fp64
# This option can be set to pass additional configuration options to
# the MFEM configuration command.
# config-opts: '-DCMAKE_VERBOSE_MAKEFILE=ON'
@@ -99,7 +101,15 @@ jobs:
mpi: par
build-system: make
hypre-target: int64
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
precision: fp64
- os: ubuntu-latest
target: opt
codecov: NO
mpi: par
build-system: make
hypre-target: int32
precision: fp32
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}-${{ matrix.precision }}
runs-on: ${{ matrix.os }}
@@ -183,25 +193,27 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-v2.2
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-${{ matrix.hypre-target }}-${{ matrix.precision }}-v2.5
- name: get hypre
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os != 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.4
uses: mfem/github-actions/build-hypre@v2.5
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: make
precision: ${{ matrix.precision }}
- name: get hypre (Windows)
if: matrix.mpi == 'par' && steps.hypre-cache.outputs.cache-hit != 'true' && matrix.os == 'windows-latest'
uses: mfem/github-actions/build-hypre@v2.4
uses: mfem/github-actions/build-hypre@v2.5
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
target: ${{ matrix.hypre-target }}
build-system: cmake
precision: ${{ matrix.precision }}
# Get Metis through cache, or build it.
# Install will only run on cache miss.
@@ -211,11 +223,11 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
- name: install metis
if: matrix.mpi == 'par' && matrix.os != 'windows-latest' && steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
uses: mfem/github-actions/build-metis@v2.5
with:
archive: ${{ matrix.os != 'macos-latest' && env.METIS_ARCHIVE || env.METIS_ARCHIVE_MAC }}
dir: ${{ env.METIS_TOP_DIR }}
@@ -242,7 +254,7 @@ jobs:
# MFEM build and test
- name: build
uses: mfem/github-actions/build-mfem@v2.4
uses: mfem/github-actions/build-mfem@v2.5
env:
VCPKG_DEFAULT_BINARY_CACHE: ${{ github.workspace }}/vcpkg_cache
with:
@@ -254,6 +266,7 @@ jobs:
hypre-dir: ${{ env.HYPRE_TOP_DIR }}
metis-dir: ${{ env.METIS_TOP_DIR }}
mfem-dir: ${{ env.MFEM_TOP_DIR }}
precision: ${{ matrix.precision }}
config-options: ${{ matrix.config-opts }}
library-only: ${{ matrix.target == 'dbg' && matrix.os != 'ubuntu-latest' }}
@@ -296,7 +309,7 @@ jobs:
# Code coverage (process and upload reports)
- name: codecov
if: matrix.codecov == 'YES'
uses: mfem/github-actions/upload-coverage@v2.4
uses: mfem/github-actions/upload-coverage@v2.5
with:
name: ${{ matrix.os }}-${{ matrix.build-system }}-${{ matrix.target }}-${{ matrix.mpi }}-${{ matrix.hypre-target }}
project_dir: ${{ env.MFEM_TOP_DIR }}
+5 -5
View File
@@ -53,11 +53,11 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.HYPRE_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.2
key: ${{ runner.os }}-build-${{ env.HYPRE_TOP_DIR }}-v2.5
- name: Get Hypre
if: steps.hypre-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-hypre@v2.4
uses: mfem/github-actions/build-hypre@v2.5
with:
archive: ${{ env.HYPRE_ARCHIVE }}
dir: ${{ env.HYPRE_TOP_DIR }}
@@ -68,18 +68,18 @@ jobs:
uses: actions/cache@v4
with:
path: ${{ env.METIS_TOP_DIR }}
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.2
key: ${{ runner.os }}-build-${{ env.METIS_TOP_DIR }}-v2.5
- name: Install Metis
if: steps.metis-cache.outputs.cache-hit != 'true'
uses: mfem/github-actions/build-metis@v2.4
uses: mfem/github-actions/build-metis@v2.5
with:
archive: ${{ env.METIS_ARCHIVE }}
dir: ${{ env.METIS_TOP_DIR }}
# MFEM build and test
- name: build-mfem
uses: mfem/github-actions/build-mfem@v2.4
uses: mfem/github-actions/build-mfem@v2.5
with:
os: ${{ runner.os }}
target: opt
+1 -1
View File
@@ -44,7 +44,7 @@ jobs:
path: mfem
- name: MFEM Build
uses: mfem/github-actions/build-mfem@v2.4
uses: mfem/github-actions/build-mfem@v2.5
with:
os: ${{ runner.os }}
target: opt
+2
View File
@@ -107,6 +107,8 @@ Miscellaneous
- Various other simplifications, extensions, and bugfixes in the code.
- Added GSLIB-based gather-scatter operator.
Version 4.6, released on September 27, 2023
===========================================
+4 -4
View File
@@ -340,9 +340,9 @@ public:
$ M^{-1} $ (currently returns NULL) */
virtual MatrixInverse *Inverse() const;
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
AssemblyLevel::LEGACY.
THe matrix that gets finalized is different if you are using static
The matrix that gets finalized is different if you are using static
condensation or hybridization.*/
virtual void Finalize(int skip_zeros = 1);
@@ -643,7 +643,7 @@ public:
void EliminateVDofs(const Array<int> &vdofs, const Vector &sol, Vector &rhs,
DiagonalPolicy dpolicy = DIAG_ONE);
/** @brief Eliminate the given @a vdofs, storing the eliminated part
/** @brief Eliminate the given @a vdofs, storing the eliminated part
internally in $ M_e $.
This method works in conjunction with EliminateVDofsInRHS() and allows
@@ -826,7 +826,7 @@ public:
$ M^{-1} $ (currently unimplemented and returns NULL)*/
virtual MatrixInverse *Inverse() const;
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
/** @brief Finalizes the matrix initialization if the ::AssemblyLevel is
AssemblyLevel::LEGACY.*/
virtual void Finalize(int skip_zeros = 1);
+2 -2
View File
@@ -101,7 +101,7 @@ void DGMassInverse::SetRelTol(const real_t rel_tol_) { rel_tol = rel_tol_; }
void DGMassInverse::SetAbsTol(const real_t abs_tol_) { abs_tol = abs_tol_; }
void DGMassInverse::SetMaxIter(const real_t max_iter_) { max_iter = max_iter_; }
void DGMassInverse::SetMaxIter(const int max_iter_) { max_iter = max_iter_; }
void DGMassInverse::Update()
{
@@ -137,7 +137,7 @@ void DGMassInverse::DGMassCGIteration(const Vector &b_, Vector &u_) const
const real_t RELTOL = rel_tol;
const real_t ABSTOL = abs_tol;
const real_t MAXIT = max_iter;
const int MAXIT = max_iter;
const bool IT_MODE = iterative_mode;
const bool CHANGE_BASIS = (d2q != nullptr);
+1 -1
View File
@@ -96,7 +96,7 @@ public:
/// Set the absolute tolerance.
void SetAbsTol(const real_t abs_tol_);
/// Set the maximum number of iterations.
void SetMaxIter(const real_t max_iter_);
void SetMaxIter(const int max_iter_);
/// Recompute operator and preconditioner (when coefficient or mesh changes).
void Update();
+77
View File
@@ -1352,6 +1352,83 @@ void OversetFindPointsGSLIB::Interpolate(const Vector &point_pos,
Interpolate(field_in, field_out);
}
GSOPGSLIB::GSOPGSLIB(Array<long long> &ids)
{
gsl_comm = new gslib::comm;
cr = new gslib::crystal;
#ifdef MFEM_USE_MPI
int initialized;
MPI_Initialized(&initialized);
if (!initialized) { MPI_Init(NULL, NULL); }
MPI_Comm comm = MPI_COMM_WORLD;
comm_init(gsl_comm, comm);
#else
comm_init(gsl_comm, 0);
#endif
crystal_init(cr, gsl_comm);
UpdateIdentifiers(ids);
}
#ifdef MFEM_USE_MPI
GSOPGSLIB::GSOPGSLIB(MPI_Comm comm_, Array<long long> &ids)
: cr(NULL), gsl_comm(NULL)
{
gsl_comm = new gslib::comm;
cr = new gslib::crystal;
comm_init(gsl_comm, comm_);
crystal_init(cr, gsl_comm);
UpdateIdentifiers(ids);
}
#endif
GSOPGSLIB::~GSOPGSLIB()
{
crystal_free(cr);
gslib_gs_free(gsl_data);
comm_free(gsl_comm);
delete gsl_comm;
delete cr;
}
void GSOPGSLIB::UpdateIdentifiers(const Array<long long> &ids)
{
long long minval = ids.Min();
MPI_Allreduce(MPI_IN_PLACE, &minval, 1, MPI_LONG_LONG_INT,
MPI_MIN, gsl_comm->c);
MFEM_VERIFY(minval >= 0, "Unique identifier cannot be negative.");
if (gsl_data != NULL) { gslib_gs_free(gsl_data); }
num_ids = ids.Size();
gsl_data = gslib_gs_setup(ids.GetData(),
ids.Size(),
gsl_comm, 0,
gslib::gs_crystal_router, 0);
}
void GSOPGSLIB::GS(Vector &senddata, GSOp op)
{
MFEM_VERIFY(senddata.Size() == num_ids,
"Incompatible setup and GOP operation.");
if (op == GSOp::ADD)
{
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_add,0,gsl_data,0);
}
else if (op == GSOp::MUL)
{
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_mul,0,gsl_data,0);
}
else if (op == GSOp::MAX)
{
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_max,0,gsl_data,0);
}
else if (op == GSOp::MIN)
{
gslib_gs(senddata.GetData(),gslib::gs_double,gslib::gs_min,0,gsl_data,0);
}
else
{
MFEM_ABORT("Invalid GSOp operation.");
}
}
} // namespace mfem
+62 -1
View File
@@ -23,13 +23,16 @@ struct comm;
struct findpts_data_2;
struct findpts_data_3;
struct crystal;
struct gs_data;
}
namespace mfem
{
/** \brief FindPointsGSLIB can robustly evaluate a GridFunction on an arbitrary
* collection of points. There are three key functions in FindPointsGSLIB:
* collection of points.
*
* There are three key functions in FindPointsGSLIB:
*
* 1. Setup - constructs the internal data structures of gslib.
*
@@ -226,6 +229,7 @@ public:
/** \brief OversetFindPointsGSLIB enables use of findpts for arbitrary number of
overlapping grids.
The parameters in this class are the same as FindPointsGSLIB with the
difference of additional inputs required to account for more than 1 mesh. */
class OversetFindPointsGSLIB : public FindPointsGSLIB
@@ -290,6 +294,63 @@ public:
using FindPointsGSLIB::Interpolate;
};
/** \brief Class for gather-scatter (gs) operations on Vectors based on
corresponding global identifiers.
This functionality is useful for gs-ops on DOF values across processor
boundary, where the global identifier would be the corresponding true DOF
index. Operations currently supported are min, max, sum, and multiplication.
Note: identifier 0 does not participate in the gather-scatter operation and
a given identifier can be included multiple times on a given rank.
For example, consider a vector, v:
- v = [0.3, 0.4, 0.25, 0.7] on rank1,
- v = [0.6, 0.1] on rank 2,
- v = [-0.2, 0.3, 0.7, 0.] on rank 3.
Consider a corresponding Array<int>, a:
- a = [1, 2, 3, 1] on rank 1,
- a = [3, 2] on rank 2,
- a = [1, 2, 0, 3] on rank 3.
A gather-scatter "minimum" operation, done as follows:
GSOPGSLIB gs = GSOPGSLIB(MPI_COMM_WORLD, a);
gs.GS(v, GSOp::MIN);
would return into v:
- v = [-0.2, 0.1, 0., -0.2] on rank 1,
- v = [0., 0.1] on rank 2,
- v = [-0.2, 0.1, 0.7, 0.] on rank 3,
where the values have been compared across all processors based on the
integer identifier. */
class GSOPGSLIB
{
protected:
struct gslib::crystal *cr; // gslib's internal data
struct gslib::comm *gsl_comm; // gslib's internal data
struct gslib::gs_data *gsl_data = NULL;
int num_ids;
public:
GSOPGSLIB(Array<long long> &ids);
#ifdef MFEM_USE_MPI
GSOPGSLIB(MPI_Comm comm_, Array<long long> &ids);
#endif
virtual ~GSOPGSLIB();
/// Supported operation types. See class description.
enum GSOp {ADD, MUL, MIN, MAX};
/// Update the identifiers used for the gather-scatter operator.
/// Same @a ids get grouped together and id == 0 does not participate.
/// See class description.
void UpdateIdentifiers(const Array<long long> &ids);
/// Gather-Scatter operation on senddata. Must match length of unique
/// identifiers used in the constructor. See class description.
void GS(Vector &senddata, GSOp op);
};
} // namespace mfem
#endif // MFEM_USE_GSLIB
+53 -49
View File
@@ -35,9 +35,9 @@ KnotVector::KnotVector(istream &input)
GetElements();
}
KnotVector::KnotVector(int Order_, int NCP)
KnotVector::KnotVector(int order, int NCP)
{
Order = Order_;
Order = order;
NumOfControlPoints = NCP;
knot.SetSize(NumOfControlPoints + Order + 1);
NumOfElements = 0;
@@ -276,18 +276,18 @@ void KnotVector::PrintFunctions(std::ostream &os, int samples) const
for (int j = 0; j <samples; j++)
{
x =j*dx;
os<< x + e;
x = j*dx;
os << x + e;
CalcShape ( shape, cnt, x);
CalcShape(shape, cnt, x);
for (int d = 0; d < Order+1; d++) { os<<"\t"<<shape[d]; }
CalcDShape ( shape, cnt, x);
CalcDShape(shape, cnt, x);
for (int d = 0; d < Order+1; d++) { os<<"\t"<<shape[d]; }
CalcD2Shape ( shape, cnt, x);
CalcD2Shape(shape, cnt, x);
for (int d = 0; d < Order+1; d++) { os<<"\t"<<shape[d]; }
os<<endl;
os << endl;
}
}
}
@@ -378,6 +378,7 @@ void KnotVector::CalcDShape(Vector &grad, int i, real_t xi) const
}
// Routine from "The NURBS book" - 2nd ed - Piegl and Tiller
// Algorithm A2.3 p. 72
void KnotVector::CalcDnShape(Vector &gradn, int n, int i, real_t xi) const
{
int p = Order, rk, pk, j1, j2,r,j,k;
@@ -522,7 +523,7 @@ void KnotVector::FindMaxima(Array<int> &ks, Vector &xi, Vector &u) const
}
arg = (arg1 + arg2)/2;
CalcShape ( shape, i, arg);
CalcShape(shape, i, arg);
max = shape[d];
}
@@ -556,7 +557,7 @@ void KnotVector::FindInterpolant(Array<Vector*> &x)
A = 0.0;
for (int i = 0; i < ncp; i++)
{
CalcShape ( shape, i_args[i], xi_args[i]);
CalcShape(shape, i_args[i], xi_args[i]);
for (int p = 0; p < order+1; p++)
{
A(i,i_args[i] + p) = shape[p];
@@ -637,9 +638,9 @@ void KnotVector::Difference(const KnotVector &kv, Vector &diff) const
}
}
void NURBSPatch::init(int dim_)
void NURBSPatch::init(int dim)
{
Dim = dim_;
Dim = dim;
sd = nd = -1;
if (kv.Size() == 1)
@@ -751,32 +752,32 @@ NURBSPatch::NURBSPatch(std::istream &input)
}
}
NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim_)
NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1, int dim)
{
kv.SetSize(2);
kv[0] = new KnotVector(*kv0);
kv[1] = new KnotVector(*kv1);
init(dim_);
init(dim);
}
NURBSPatch::NURBSPatch(const KnotVector *kv0, const KnotVector *kv1,
const KnotVector *kv2, int dim_)
const KnotVector *kv2, int dim)
{
kv.SetSize(3);
kv[0] = new KnotVector(*kv0);
kv[1] = new KnotVector(*kv1);
kv[2] = new KnotVector(*kv2);
init(dim_);
init(dim);
}
NURBSPatch::NURBSPatch(Array<const KnotVector *> &kv_, int dim_)
NURBSPatch::NURBSPatch(Array<const KnotVector *> &kvs, int dim)
{
kv.SetSize(kv_.Size());
kv.SetSize(kvs.Size());
for (int i = 0; i < kv.Size(); i++)
{
kv[i] = new KnotVector(*kv_[i]);
kv[i] = new KnotVector(*kvs[i]);
}
init(dim_);
init(dim);
}
NURBSPatch::NURBSPatch(NURBSPatch *parent, int dir, int Order, int NCP)
@@ -859,7 +860,7 @@ void NURBSPatch::Print(std::ostream &os) const
int NURBSPatch::SetLoopDirection(int dir)
{
if (nj == -1)
if (nj == -1) // 1D case
{
if (dir == 0)
{
@@ -875,7 +876,7 @@ int NURBSPatch::SetLoopDirection(int dir)
mfem_error();
}
}
else if (nk == -1)
else if (nk == -1) // 2D case
{
if (dir == 0)
{
@@ -898,7 +899,7 @@ int NURBSPatch::SetLoopDirection(int dir)
mfem_error();
}
}
else
else // 3D case
{
if (dir == 0)
{
@@ -992,6 +993,7 @@ void NURBSPatch::GetCoarseningFactors(Array<int> & f) const
void NURBSPatch::KnotInsert(Array<KnotVector *> &newkv)
{
MFEM_ASSERT(newkv.Size() == kv.Size(), "Invalid input to KnotInsert");
for (int dir = 0; dir < kv.Size(); dir++)
{
KnotInsert(dir, *newkv[dir]);
@@ -1026,6 +1028,7 @@ void NURBSPatch::KnotInsert(int dir, const KnotVector &newkv)
void NURBSPatch::KnotInsert(Array<Vector *> &newkv)
{
MFEM_ASSERT(newkv.Size() == kv.Size(), "Invalid input to KnotInsert");
for (int dir = 0; dir < kv.Size(); dir++)
{
KnotInsert(dir, *newkv[dir]);
@@ -1143,7 +1146,7 @@ void NURBSPatch::KnotInsert(int dir, const Vector &knot)
for (int ll = 0; ll < size; ll++)
{
newp.slice(ind-1,ll) = alfa*newp.slice(ind-1,ll) +
(1.0-alfa)*newp.slice(ind, ll);
(1.0-alfa)*newp.slice(ind,ll);
}
}
}
@@ -1372,6 +1375,8 @@ void NURBSPatch::DegreeElevate(int dir, int t)
mfem_error("NURBSPatch::DegreeElevate : Incorrect direction!");
}
MFEM_ASSERT(t >= 0, "DegreeElevate cannot decrease the degree.");
int i, j, k, kj, mpi, mul, mh, kind, cind, first, last;
int r, a, b, oldr, save, s, tr, lbz, rbz, l;
real_t inv, ua, ub, numer, alf, den, bet, gam;
@@ -1715,8 +1720,10 @@ void NURBSPatch::Get3DRotationMatrix(real_t n[], real_t angle, real_t r,
DenseMatrix &T)
{
real_t c, s, c1;
real_t l2 = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
real_t l = sqrt(l2);
const real_t l2 = n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
const real_t l = sqrt(l2);
MFEM_ASSERT(l2 > 0.0, "3D rotation axis is undefined");
if (fabs(angle) == (real_t)(M_PI_2))
{
@@ -1973,7 +1980,7 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
// Read topology
patchTopo = new Mesh;
patchTopo->LoadPatchTopo(input, edge_to_knot);
own_topo = 1;
own_topo = true;
CheckPatches();
// CheckBdrPatches();
@@ -2172,7 +2179,7 @@ NURBSExtension::NURBSExtension(std::istream &input, bool spacing)
NURBSExtension::NURBSExtension(NURBSExtension *parent, int newOrder)
{
patchTopo = parent->patchTopo;
own_topo = 0;
own_topo = false;
parent->edge_to_knot.Copy(edge_to_knot);
@@ -2229,7 +2236,7 @@ NURBSExtension::NURBSExtension(NURBSExtension *parent,
SetOrderFromOrders();
patchTopo = parent->patchTopo;
own_topo = 0;
own_topo = false;
parent->edge_to_knot.Copy(edge_to_knot);
@@ -2287,8 +2294,8 @@ NURBSExtension::NURBSExtension(Mesh *mesh_array[], int num_pieces)
" parent does not own the patch topology!");
}
patchTopo = parent->patchTopo;
own_topo = 1;
parent->own_topo = 0;
own_topo = true;
parent->own_topo = false;
parent->edge_to_knot.Copy(edge_to_knot);
@@ -2442,7 +2449,7 @@ void NURBSExtension::PrintFunctions(const char *basename, int samples) const
for (int i = 0; i < NumOfKnotVectors; i++)
{
std::ostringstream filename;
filename << basename<<"_"<<i<<".dat";
filename << basename << "_" << i << ".dat";
os.open(filename.str().c_str());
knotVectors[i]->PrintFunctions(os,samples);
os.close();
@@ -2889,7 +2896,6 @@ void NURBSExtension::CheckKVDirection(int p, Array <int> &kvdir)
// -1: direction is flipped
// 1: direction is not flipped
for (int i = 0; i < edges.Size(); i++)
{
// First side
@@ -3069,7 +3075,7 @@ void NURBSExtension::UpdateUniqueKV()
bool NURBSExtension::ConsistentKVSets()
{
// patchTopo->GetElementEdges is not yet implemented for 1D
MFEM_VERIFY(Dimension()>1, "1D not yet implemented.");
MFEM_VERIFY(Dimension() > 1, "1D not yet implemented.");
Array<int> edges, orient, kvdir;
Vector diff;
@@ -3180,7 +3186,7 @@ const
}
}
void NURBSExtension::GetBdrPatchKnotVectors(int p, Array<KnotVector *> &kv)
void NURBSExtension::GetBdrPatchKnotVectors(int bp, Array<KnotVector *> &kv)
{
Array<int> edges;
Array<int> orient;
@@ -3189,19 +3195,19 @@ void NURBSExtension::GetBdrPatchKnotVectors(int p, Array<KnotVector *> &kv)
if (Dimension() == 2)
{
patchTopo->GetBdrElementEdges(p, edges, orient);
patchTopo->GetBdrElementEdges(bp, edges, orient);
kv[0] = KnotVec(edges[0]);
}
else if (Dimension() == 3)
{
patchTopo->GetBdrElementEdges(p, edges, orient);
patchTopo->GetBdrElementEdges(bp, edges, orient);
kv[0] = KnotVec(edges[0]);
kv[1] = KnotVec(edges[1]);
}
}
void NURBSExtension::GetBdrPatchKnotVectors(
int p, Array<const KnotVector *> &kv) const
int bp, Array<const KnotVector *> &kv) const
{
Array<int> edges;
Array<int> orient;
@@ -3210,12 +3216,12 @@ void NURBSExtension::GetBdrPatchKnotVectors(
if (Dimension() == 2)
{
patchTopo->GetBdrElementEdges(p, edges, orient);
patchTopo->GetBdrElementEdges(bp, edges, orient);
kv[0] = KnotVec(edges[0]);
}
else if (Dimension() == 3)
{
patchTopo->GetBdrElementEdges(p, edges, orient);
patchTopo->GetBdrElementEdges(bp, edges, orient);
kv[0] = KnotVec(edges[0]);
kv[1] = KnotVec(edges[1]);
}
@@ -3305,8 +3311,6 @@ void NURBSExtension::GenerateOffsets()
p_meshOffsets[p] = meshCounter;
p_spaceOffsets[p] = spaceCounter;
if (dim == 1)
{
meshCounter += KnotVec(0)->GetNE() - 1;
@@ -4748,8 +4752,8 @@ ParNURBSExtension::ParNURBSExtension(MPI_Comm comm, NURBSExtension *parent,
mfem_error("ParNURBSExtension::ParNURBSExtension :\n"
" parent does not own the patch topology!");
}
own_topo = 1;
parent->own_topo = 0;
own_topo = true;
parent->own_topo = false;
parent->edge_to_knot.Copy(edge_to_knot);
@@ -4812,7 +4816,7 @@ ParNURBSExtension::ParNURBSExtension(NURBSExtension *parent,
patchTopo = parent->patchTopo;
own_topo = parent->own_topo;
parent->own_topo = 0;
parent->own_topo = false;
Swap(edge_to_knot, parent->edge_to_knot);
@@ -5057,7 +5061,7 @@ Table *ParNURBSExtension::Get3DGlobalElementDofTable()
return (new Table(GetGNE(), gel_dof_list));
}
void ParNURBSExtension::SetActive(const int *partitioning_,
void ParNURBSExtension::SetActive(const int *partition,
const Array<bool> &active_bel)
{
activeElem.SetSize(GetGNE());
@@ -5065,7 +5069,7 @@ void ParNURBSExtension::SetActive(const int *partitioning_,
NumOfActiveElems = 0;
const int MyRank = gtopo.MyRank();
for (int i = 0; i < GetGNE(); i++)
if (partitioning_[i] == MyRank)
if (partition[i] == MyRank)
{
activeElem[i] = true;
NumOfActiveElems++;
@@ -5080,7 +5084,7 @@ void ParNURBSExtension::SetActive(const int *partitioning_,
}
}
void ParNURBSExtension::BuildGroups(const int *partitioning_,
void ParNURBSExtension::BuildGroups(const int *partition,
const Table &elem_dof)
{
Table dof_proc;
@@ -5092,7 +5096,7 @@ void ParNURBSExtension::BuildGroups(const int *partitioning_,
// convert elements to processors
for (int i = 0; i < dof_proc.Size_of_connections(); i++)
{
dof_proc.GetJ()[i] = partitioning_[dof_proc.GetJ()[i]];
dof_proc.GetJ()[i] = partition[dof_proc.GetJ()[i]];
}
// the first group is the local one
+442 -143
View File
File diff suppressed because it is too large Load Diff
+68
View File
@@ -368,5 +368,73 @@ TEST_CASE("GSLIBInterpolateL2ElementBoundary",
delete c_fec;
}
#ifdef MFEM_USE_MPI
TEST_CASE("GSLIBGSOP", "[GSLIBGSOP][Parallel][GSLIB]")
{
int myid;
MPI_Comm_rank(MPI_COMM_WORLD, &myid);
int nlen = 5 + rand() % 1000;
MPI_Allreduce(MPI_IN_PLACE, &nlen, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD);
Array<long long> ids(nlen);
Vector vals(nlen);
vals.Randomize(myid+1);
// Force minimum values based on the identifier for deterministic behavior
// on rank 0 and randomize the identifier on other ranks.
if (myid == 0)
{
for (int i = 0; i < nlen; i++)
{
ids[i] = i+1;
vals(i) = -ids[i];
}
}
else
{
for (int i = 0; i < nlen; i++)
{
int num = rand() % nlen + 1;
ids[i] = num;
}
}
// Test GSOp::MIN
GSOPGSLIB gs = GSOPGSLIB(MPI_COMM_WORLD, ids);
gs.GS(vals, GSOPGSLIB::GSOp::MIN);
// Check for minimum value
for (int i = 0; i < nlen; i++)
{
int id = ids[i];
REQUIRE(vals(i) == -1.0*id);
}
// Test GSOp::ADD
// Set all values to 0 except on rank 0, and then add them.
if (myid != 0) { vals = 0.0; }
gs.GS(vals, GSOPGSLIB::GSOp::ADD);
// Check for added value to match what was originally set on rank 0.
for (int i = 0; i < nlen; i++)
{
int id = ids[i];
REQUIRE(vals(i) == -1.0*id);
}
// Test GSOp::MUL
// Randomize values on all ranks except rank 0 such that they are positive.
if (myid != 0) { vals.Randomize(); }
gs.GS(vals, GSOPGSLIB::GSOp::MUL);
// Check for multipled values to be negative
for (int i = 0; i < nlen; i++)
{
REQUIRE(vals(i) < 0);
}
}
#endif
} //namespace_gslib
#endif