Merge remote-tracking branch 'origin/master' into hughcars/nc-internal-bdr-project-fix
This commit is contained in:
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
===========================================
|
||||
|
||||
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user